Merge "Use SparseArray instead of HashMap in vCard code"
diff --git a/src/com/android/contacts/SpecialCharSequenceMgr.java b/src/com/android/contacts/SpecialCharSequenceMgr.java
index b5deab8..aa6faec 100644
--- a/src/com/android/contacts/SpecialCharSequenceMgr.java
+++ b/src/com/android/contacts/SpecialCharSequenceMgr.java
@@ -28,6 +28,7 @@
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Telephony.Intents;
@@ -54,6 +55,23 @@
private static final String TAG = "SpecialCharSequenceMgr";
private static final String MMI_IMEI_DISPLAY = "*#06#";
+ /**
+ * Remembers the previous {@link QueryHandler} and cancel the operation when needed, to
+ * prevent possible crash.
+ *
+ * QueryHandler may call {@link ProgressDialog#dismiss()} when the screen is already gone,
+ * which will cause the app crash. This variable enables the class to prevent the crash
+ * on {@link #cleanup()}.
+ *
+ * TODO: Remove this and replace it (and {@link #cleanup()}) with better implementation.
+ * One complication is that we have SpecialCharSequencMgr in Phone package too, which has
+ * *slightly* different implementation. Note that Phone package doesn't have this problem,
+ * so the class on Phone side doesn't have this functionality.
+ * Fundamental fix would be to have one shared implementation and resolve this corner case more
+ * gracefully.
+ */
+ private static QueryHandler sPreviousAdnQueryHandler;
+
/** This class is never instantiated. */
private SpecialCharSequenceMgr() {
}
@@ -83,6 +101,23 @@
}
/**
+ * Cleanup everything around this class. Must be run inside the main thread.
+ *
+ * This should be called when the screen becomes background.
+ */
+ public static void cleanup() {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ Log.wtf(TAG, "cleanup() is called outside the main thread");
+ return;
+ }
+
+ if (sPreviousAdnQueryHandler != null) {
+ sPreviousAdnQueryHandler.cancel();
+ sPreviousAdnQueryHandler = null;
+ }
+ }
+
+ /**
* Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.
* If a secret code is encountered an Intent is started with the android_secret_code://<code>
* URI.
@@ -164,6 +199,12 @@
// run the query.
handler.startQuery(ADN_QUERY_TOKEN, sc, Uri.parse("content://icc/adn"),
new String[]{ADN_PHONE_NUMBER_COLUMN_NAME}, null, null, null);
+
+ if (sPreviousAdnQueryHandler != null) {
+ // It is harmless to call cancel() even after the handler's gone.
+ sPreviousAdnQueryHandler.cancel();
+ }
+ sPreviousAdnQueryHandler = handler;
return true;
} catch (NumberFormatException ex) {
// Ignore
@@ -304,6 +345,8 @@
*/
private static class QueryHandler extends AsyncQueryHandler {
+ private boolean mCanceled;
+
public QueryHandler(ContentResolver cr) {
super(cr);
}
@@ -314,6 +357,11 @@
*/
@Override
protected void onQueryComplete(int token, Object cookie, Cursor c) {
+ sPreviousAdnQueryHandler = null;
+ if (mCanceled) {
+ return;
+ }
+
SimContactQueryCookie sc = (SimContactQueryCookie) cookie;
// close the progress dialog.
@@ -339,5 +387,12 @@
.show();
}
}
+
+ public void cancel() {
+ mCanceled = true;
+ // Ask AsyncQueryHandler to cancel the whole request. This will fails when the
+ // query already started.
+ cancelOperation(ADN_QUERY_TOKEN);
+ }
}
}
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index a49ce8a..f58f3e3 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -574,6 +574,8 @@
// TODO: I wonder if we should not check if the AsyncTask that
// lookup the last dialed number has completed.
mLastNumberDialed = EMPTY_NUMBER; // Since we are going to query again, free stale number.
+
+ SpecialCharSequenceMgr.cleanup();
}
@Override