summaryrefslogtreecommitdiffstats
path: root/src/com/android/browser/AutofillHandler.java
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2012-05-14 16:39:50 +0100
committerBen Murdoch <benm@google.com>2012-05-16 18:05:38 +0100
commit234eadcf7d0dbf2d24f92c24f40343d518f6fe3a (patch)
tree3c06d8f77a653ef05940c049c549826ebca0569d /src/com/android/browser/AutofillHandler.java
parent54217b39d7d097f2f4fe9fac928a1c3bf1b9f13f (diff)
downloadandroid_packages_apps_Gello-234eadcf7d0dbf2d24f92c24f40343d518f6fe3a.tar.gz
android_packages_apps_Gello-234eadcf7d0dbf2d24f92c24f40343d518f6fe3a.tar.bz2
android_packages_apps_Gello-234eadcf7d0dbf2d24f92c24f40343d518f6fe3a.zip
Don't wait on ContactsProvider
Right now during the initial WebSettings sync to native we wait for the autofill profile to be loaded from disk so that it can be synced. If there's no profile set, then we try to infer a profile from the user's Me contact profile. Querying the Me contact can be slow and in some extreme cases can cause the settings sync on the UI thread to block long enough to show an ANR. Instead signal the threads (via the CountdownLatch) waiting on the initial import before we do the Me profile lookup. Note that we still may block the UI thread if the lookup of an already saved profile takes an exceptionally long time. This is so that when a user has saved a profile, we'll never resort to showing them the "setup autofill" message. (But all ANR reports to date have shown that we were querying the Me contact at the time of ANR). Bug: 6371781 Change-Id: Ibb0d5e285ec3587d9f9bad3e69b79890850c2f6d
Diffstat (limited to 'src/com/android/browser/AutofillHandler.java')
-rw-r--r--src/com/android/browser/AutofillHandler.java61
1 files changed, 43 insertions, 18 deletions
diff --git a/src/com/android/browser/AutofillHandler.java b/src/com/android/browser/AutofillHandler.java
index 99ee6a0b..5b0320da 100644
--- a/src/com/android/browser/AutofillHandler.java
+++ b/src/com/android/browser/AutofillHandler.java
@@ -26,6 +26,7 @@ import android.os.AsyncTask;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
+import android.util.Log;
import android.webkit.WebSettingsClassic.AutoFillProfile;
import java.util.concurrent.CountDownLatch;
@@ -43,6 +44,8 @@ public class AutofillHandler {
private CountDownLatch mLoaded = new CountDownLatch(1);
private Context mContext;
+ private static final String LOGTAG = "AutofillHandler";
+
public AutofillHandler(Context context) {
mContext = context.getApplicationContext();
}
@@ -62,18 +65,24 @@ public class AutofillHandler {
new LoadFromDb().start();
}
- public void waitForLoad() {
+ private void waitForLoad() {
try {
mLoaded.await();
- } catch (InterruptedException e) {}
+ } catch (InterruptedException e) {
+ Log.w(LOGTAG, "Caught exception while waiting for AutofillProfile to load.");
+ }
}
private class LoadFromDb extends Thread {
@Override
public void run() {
- SharedPreferences p =
- PreferenceManager.getDefaultSharedPreferences(mContext);
+ // Note the lack of synchronization over mAutoFillActiveProfileId and
+ // mAutoFillProfile here. This is because we control all other access
+ // to these members through the public functions of this class, and they
+ // all wait for this thread via the mLoaded CountDownLatch.
+
+ SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(mContext);
// Read the last active AutoFill profile id.
mAutoFillActiveProfileId = p.getInt(
@@ -82,7 +91,9 @@ public class AutofillHandler {
// Load the autofill profile data from the database. We use a database separate
// to the browser preference DB to make it easier to support multiple profiles
- // and switching between them.
+ // and switching between them. Note that this may block startup if this DB lookup
+ // is extremely slow. We do this to ensure that if there's a profile set, the
+ // user never sees the "setup Autofill" option.
AutoFillProfileDatabase autoFillDb = AutoFillProfileDatabase.getInstance(mContext);
Cursor c = autoFillDb.getProfile(mAutoFillActiveProfileId);
@@ -116,12 +127,19 @@ public class AutofillHandler {
c.close();
autoFillDb.close();
+ // At this point we've loaded the profile if there was one, so let any thread
+ // waiting on initialization continue.
+ mLoaded.countDown();
+
+ // Synchronization note: strictly speaking, it's possible that mAutoFillProfile
+ // may get a value after we check below, but that's OK. This check is only an
+ // optimisation, and we do a proper synchronized check further down when it comes
+ // to actually setting the inferred profile.
if (mAutoFillProfile == null) {
- // We did not load a profile from disk. Try to populate one with the user's
+ // We did not load a profile from disk. Try to infer one from the user's
// "me" contact.
final Uri profileUri = Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
-
String name = getContactField(profileUri,
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
@@ -143,13 +161,16 @@ public class AutofillHandler {
// When querying structured postal data, it often all comes back as a string
// inside the "street" field.
- mAutoFillProfile = new AutoFillProfile(
- 1, name, email, company, null, null, null, null,
- null, null, phone);
+ synchronized(AutofillHandler.this) {
+ // Only use this profile if one hasn't been set inbetween the
+ // inital import and this thread getting to this point.
+ if (mAutoFillProfile == null) {
+ setAutoFillProfile(new AutoFillProfile(1, name, email, company,
+ null, null, null, null, null, null, phone), null);
+ }
+ }
}
}
-
- mLoaded.countDown();
}
private String getContactField(Uri uri, String field, String itemType) {
@@ -174,7 +195,8 @@ public class AutofillHandler {
}
}
- public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
+ public synchronized void setAutoFillProfile(AutoFillProfile profile, Message msg) {
+ waitForLoad();
int profileId = NO_AUTOFILL_PROFILE_SET;
if (profile != null) {
profileId = profile.getUniqueId();
@@ -193,11 +215,12 @@ public class AutofillHandler {
setActiveAutoFillProfileId(profileId);
}
- public AutoFillProfile getAutoFillProfile() {
+ public synchronized AutoFillProfile getAutoFillProfile() {
+ waitForLoad();
return mAutoFillProfile;
}
- private void setActiveAutoFillProfileId(int activeProfileId) {
+ private synchronized void setActiveAutoFillProfileId(int activeProfileId) {
mAutoFillActiveProfileId = activeProfileId;
Editor ed = PreferenceManager.
getDefaultSharedPreferences(mContext).edit();
@@ -234,9 +257,11 @@ public class AutofillHandler {
@Override
protected Void doInBackground(AutoFillProfile... values) {
mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
- assert mAutoFillActiveProfileId != NO_AUTOFILL_PROFILE_SET;
- AutoFillProfile newProfile = values[0];
- mAutoFillProfileDb.addOrUpdateProfile(mAutoFillActiveProfileId, newProfile);
+ synchronized (AutofillHandler.this) {
+ assert mAutoFillActiveProfileId != NO_AUTOFILL_PROFILE_SET;
+ AutoFillProfile newProfile = values[0];
+ mAutoFillProfileDb.addOrUpdateProfile(mAutoFillActiveProfileId, newProfile);
+ }
return null;
}
}