From: Jeff Sharkey Date: Fri, 10 Jul 2009 22:24:29 +0000 (-0700) Subject: Handle full-disk exceptions when viewing call log. X-Git-Tag: android-x86-1.6~1^2~2 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fpackages-apps-Contacts.git;a=commitdiff_plain;h=9be3f5b6135b4b48f65f87f1a221c1ab5d5b4f89 Handle full-disk exceptions when viewing call log. When the internal storage is full, resetNewCallsFlag() fails and causes Contacts to crash. Since this method is called whenever the tab is opened, it makes the call log inaccessible to users. (We should always keep the phone in a usable state, even when the disk is full.) Because startUpdate() runs on a background thread, I'm overriding the WorkerHandler used by AsyncQueryHandler to wrap any calls in a try/catch block. Also added a try/catch block around the code that updates any missing contact details after a caller-ID query has returned, which could also cause a crash when the user switches to the call log tab. Partially fixes http://b/issue?id=1966505 --- diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java index 6abaf23..54e9a05 100644 --- a/src/com/android/contacts/RecentCallsListActivity.java +++ b/src/com/android/contacts/RecentCallsListActivity.java @@ -24,10 +24,14 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabaseCorruptException; +import android.database.sqlite.SQLiteDiskIOException; +import android.database.sqlite.SQLiteFullException; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -147,18 +151,18 @@ public class RecentCallsListActivity extends ListActivity int numberType; String numberLabel; } - + /** * Shared builder used by {@link #formatPhoneNumber(String)} to minimize * allocations when formatting phone numbers. */ private static final SpannableStringBuilder sEditable = new SpannableStringBuilder(); - + /** * Invalid formatting type constant for {@link #sFormattingType}. */ private static final int FORMATTING_TYPE_INVALID = -1; - + /** * Cached formatting type for current {@link Locale}, as provided by * {@link PhoneNumberUtils#getFormatTypeForLocale(Locale)}. @@ -277,9 +281,17 @@ public class RecentCallsListActivity extends ListActivity values.put(Calls.CACHED_NAME, ci.name); values.put(Calls.CACHED_NUMBER_TYPE, ci.type); values.put(Calls.CACHED_NUMBER_LABEL, ci.label); - RecentCallsListActivity.this.getContentResolver().update( - Calls.CONTENT_URI, - values, Calls.NUMBER + "='" + ciq.number + "'", null); + + try { + RecentCallsListActivity.this.getContentResolver().update(Calls.CONTENT_URI, values, + Calls.NUMBER + "='" + ciq.number + "'", null); + } catch (SQLiteDiskIOException e) { + Log.w(TAG, "Exception while updating call info", e); + } catch (SQLiteFullException e) { + Log.w(TAG, "Exception while updating call info", e); + } catch (SQLiteDatabaseCorruptException e) { + Log.w(TAG, "Exception while updating call info", e); + } } private void enqueueRequest(String number, int position, @@ -320,7 +332,7 @@ public class RecentCallsListActivity extends ListActivity info.type = phonesCursor.getInt(PHONE_TYPE_COLUMN_INDEX); info.label = phonesCursor.getString(LABEL_COLUMN_INDEX); info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX); - + // New incoming phone number invalidates our formatted // cache. Any cache fills happen only on the GUI thread. info.formattedNumber = null; @@ -378,7 +390,7 @@ public class RecentCallsListActivity extends ListActivity views.iconView = (ImageView) view.findViewById(R.id.call_type_icon); views.callView = view.findViewById(R.id.call_icon); views.callView.setOnClickListener(this); - + view.setTag(views); return view; @@ -394,7 +406,7 @@ public class RecentCallsListActivity extends ListActivity String callerName = c.getString(CALLER_NAME_COLUMN_INDEX); int callerNumberType = c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX); - + // Store away the number so we can call it directly if you click on the call icon views.callView.setTag(number); @@ -418,7 +430,7 @@ public class RecentCallsListActivity extends ListActivity enqueueRequest(number, c.getPosition(), callerName, callerNumberType, callerNumberLabel); } - + // Format and cache phone number for found contact if (info.formattedNumber == null) { info.formattedNumber = formatPhoneNumber(info.number); @@ -436,7 +448,7 @@ public class RecentCallsListActivity extends ListActivity name = callerName; ntype = callerNumberType; label = callerNumberLabel; - + // Format the cached call_log phone number formattedNumber = formatPhoneNumber(number); } @@ -478,7 +490,7 @@ public class RecentCallsListActivity extends ListActivity // Set the date/time field by mixing relative and absolute times. int flags = DateUtils.FORMAT_ABBREV_RELATIVE; - + views.dateView.setText(DateUtils.getRelativeTimeSpanString(date, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, flags)); @@ -509,6 +521,36 @@ public class RecentCallsListActivity extends ListActivity private static final class QueryHandler extends AsyncQueryHandler { private final WeakReference mActivity; + /** + * Simple handler that wraps background calls to catch + * {@link SQLiteException}, such as when the disk is full. + */ + protected class CatchingWorkerHandler extends AsyncQueryHandler.WorkerHandler { + public CatchingWorkerHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + try { + // Perform same query while catching any exceptions + super.handleMessage(msg); + } catch (SQLiteDiskIOException e) { + Log.w(TAG, "Exception on background worker thread", e); + } catch (SQLiteFullException e) { + Log.w(TAG, "Exception on background worker thread", e); + } catch (SQLiteDatabaseCorruptException e) { + Log.w(TAG, "Exception on background worker thread", e); + } + } + } + + @Override + protected Handler createHandler(Looper looper) { + // Provide our special handler that catches exceptions + return new CatchingWorkerHandler(looper); + } + public QueryHandler(Context context) { super(context.getContentResolver()); mActivity = new WeakReference( @@ -544,11 +586,11 @@ public class RecentCallsListActivity extends ListActivity mVoiceMailNumber = ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)) .getVoiceMailNumber(); mQueryHandler = new QueryHandler(this); - + // Reset locale-based formatting cache sFormattingType = FORMATTING_TYPE_INVALID; } - + @Override protected void onResume() { // The adapter caches looked up numbers, clear it so they will get @@ -586,7 +628,7 @@ public class RecentCallsListActivity extends ListActivity @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); - + // Clear notifications only when window gains focus. This activity won't // immediately receive focus if the keyguard screen is above it. if (hasFocus) { @@ -619,10 +661,10 @@ public class RecentCallsListActivity extends ListActivity if (sFormattingType == FORMATTING_TYPE_INVALID) { sFormattingType = PhoneNumberUtils.getFormatTypeForLocale(Locale.getDefault()); } - + sEditable.clear(); sEditable.append(number); - + PhoneNumberUtils.formatNumber(sEditable, sFormattingType); return sEditable.toString(); }