Merge "Remove assistant timeouts from Experiments" into ub-contactsdialer-i-dev
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index be583b0..c9153e1 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -76,8 +76,10 @@
 import com.android.contacts.model.RawContactDeltaList;
 import com.android.contacts.model.RawContactModifier;
 import com.android.contacts.model.ValuesDelta;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.AccountsLoader;
 import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.quickcontact.InvisibleContactUtil;
 import com.android.contacts.quickcontact.QuickContactActivity;
@@ -95,6 +97,7 @@
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -114,6 +117,7 @@
 
     private static final int LOADER_CONTACT = 1;
     private static final int LOADER_GROUPS = 2;
+    private static final int LOADER_ACCOUNTS = 3;
 
     private static final String KEY_PHOTO_RAW_CONTACT_ID = "photo_raw_contact_id";
     private static final String KEY_UPDATED_PHOTOS = "updated_photos";
@@ -342,6 +346,7 @@
     // Whether to show the new contact blank form and if it's corresponding delta is ready.
     protected boolean mHasNewContact;
     protected AccountWithDataSet mAccountWithDataSet;
+    protected List<AccountInfo> mWritableAccounts = Collections.emptyList();
     protected boolean mNewContactDataReady;
     protected boolean mNewContactAccountChanged;
 
@@ -430,6 +435,48 @@
                 }
             };
 
+    protected LoaderManager.LoaderCallbacks<List<AccountInfo>> mAccountsLoaderListener =
+            new LoaderManager.LoaderCallbacks<List<AccountInfo>>() {
+                @Override
+                public Loader<List<AccountInfo>> onCreateLoader(int id, Bundle args) {
+                    return new AccountsLoader(getActivity(), AccountTypeManager.writableFilter());
+                }
+
+                @Override
+                public void onLoadFinished(
+                        Loader<List<AccountInfo>> loader, List<AccountInfo> data) {
+                    mWritableAccounts = data;
+
+                    final RawContactEditorView view = getContent();
+                    if (view == null) {
+                        return;
+                    }
+                    view.setAccounts(data);
+                    if (mAccountWithDataSet == null && view.getCurrentRawContactDelta() == null) {
+                        return;
+                    }
+
+                    final AccountWithDataSet account = mAccountWithDataSet != null
+                            ? mAccountWithDataSet
+                            : view.getCurrentRawContactDelta().getAccountWithDataSet();
+
+                    // The current account was removed
+                    if (!AccountInfo.contains(data, account) && !data.isEmpty()) {
+                        if (isReadyToBindEditors()) {
+                            onRebindEditorsForNewContact(getContent().getCurrentRawContactDelta(),
+                                    account, data.get(0).getAccount());
+                        } else {
+                            mAccountWithDataSet = data.get(0).getAccount();
+                        }
+                    }
+                }
+
+                @Override
+                public void onLoaderReset(Loader<List<AccountInfo>> loader) {
+                }
+            };
+
+
     private long mPhotoRawContactId;
     private Bundle mUpdatedPhotos = new Bundle();
 
@@ -520,6 +567,10 @@
 
         validateAction(mAction);
 
+        if (!Intent.ACTION_EDIT.equals(mAction)) {
+            getLoaderManager().initLoader(LOADER_ACCOUNTS, null, mAccountsLoaderListener);
+        }
+
         if (mState.isEmpty()) {
             // The delta list may not have finished loading before orientation change happens.
             // In this case, there will be a saved state but deltas will be missing.  Reload from
diff --git a/src/com/android/contacts/editor/EditorUiUtils.java b/src/com/android/contacts/editor/EditorUiUtils.java
index 0810ab8..23c7fa0 100644
--- a/src/com/android/contacts/editor/EditorUiUtils.java
+++ b/src/com/android/contacts/editor/EditorUiUtils.java
@@ -50,6 +50,7 @@
 import com.android.contacts.R;
 import com.android.contacts.model.ValuesDelta;
 import com.android.contacts.model.account.AccountDisplayInfo;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.dataitem.DataKind;
 import com.android.contacts.util.ContactPhotoUtils;
 import com.android.contacts.util.MaterialColorMapUtils.MaterialPalette;
@@ -112,12 +113,12 @@
 
 
     public static String getAccountHeaderLabelForMyProfile(Context context,
-            AccountDisplayInfo displayableAccount) {
-        if (displayableAccount.isDeviceAccount()) {
+            AccountInfo accountInfo) {
+        if (accountInfo.isDeviceAccount()) {
             return context.getString(R.string.local_profile_title);
         } else {
             return context.getString(R.string.external_profile_title,
-                    displayableAccount.getTypeLabel());
+                    accountInfo.getTypeLabel());
         }
     }
 
diff --git a/src/com/android/contacts/editor/PickRawContactDialogFragment.java b/src/com/android/contacts/editor/PickRawContactDialogFragment.java
index 93b9932..d894371 100644
--- a/src/com/android/contacts/editor/PickRawContactDialogFragment.java
+++ b/src/com/android/contacts/editor/PickRawContactDialogFragment.java
@@ -27,6 +27,7 @@
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.account.AccountDisplayInfo;
 import com.android.contacts.model.account.AccountDisplayInfoFactory;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.account.GoogleAccountType;
@@ -114,12 +115,12 @@
 
             // Use the same string as editor if it's an editable user profile raw contact.
             if (mRawContactsMetadata.isUserProfile && account.areContactsWritable()) {
-                final AccountDisplayInfo displayInfo =
-                        mAccountDisplayInfoFactory.getAccountDisplayInfo(
+                final AccountInfo accountInfo =
+                        AccountTypeManager.getInstance(getContext()).getAccountInfoForAccount(
                                 new AccountWithDataSet(rawContact.accountName,
                                         rawContact.accountType, rawContact.accountDataSet));
                 accountDisplayLabel = EditorUiUtils.getAccountHeaderLabelForMyProfile(mContext,
-                        displayInfo);
+                        accountInfo);
             } else if (GoogleAccountType.ACCOUNT_TYPE.equals(rawContact.accountType)
                     && account.dataSet == null) {
                 // Focus Google accounts have the account name shown
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 4711bcb..450d8c0 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -60,6 +60,7 @@
 import com.android.contacts.model.ValuesDelta;
 import com.android.contacts.model.account.AccountDisplayInfo;
 import com.android.contacts.model.account.AccountDisplayInfoFactory;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.dataitem.CustomDataItem;
@@ -71,6 +72,7 @@
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
@@ -196,7 +198,6 @@
     private RawContactEditorView.Listener mListener;
 
     private AccountTypeManager mAccountTypeManager;
-    private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
     private LayoutInflater mLayoutInflater;
 
     private ViewIdGenerator mViewIdGenerator;
@@ -204,6 +205,7 @@
     private boolean mHasNewContact;
     private boolean mIsUserProfile;
     private AccountWithDataSet mPrimaryAccount;
+    private List<AccountInfo> mAccounts = new ArrayList<>();
     private RawContactDeltaList mRawContactDeltas;
     private RawContactDelta mCurrentRawContactDelta;
     private long mRawContactIdToDisplayAlone = -1;
@@ -248,7 +250,6 @@
         super.onFinishInflate();
 
         mAccountTypeManager = AccountTypeManager.getInstance(getContext());
-        mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(getContext());
         mLayoutInflater = (LayoutInflater)
                 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
@@ -499,6 +500,13 @@
         if (mListener != null) mListener.onEditorsBound();
     }
 
+    public void setAccounts(List<AccountInfo> accounts) {
+        mAccounts.clear();
+        mAccounts.addAll(accounts);
+        // Update the account header
+        setAccountInfo();
+    }
+
     private void setupEditorNormally() {
         addKindSectionViews();
 
@@ -711,8 +719,19 @@
     }
 
     private void setAccountInfo() {
-        final AccountDisplayInfo account =
-                mAccountDisplayInfoFactory.getAccountDisplayInfoFor(mCurrentRawContactDelta);
+        if (mCurrentRawContactDelta == null && mPrimaryAccount == null) {
+            return;
+        }
+        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(getContext());
+        final AccountInfo account = mCurrentRawContactDelta != null
+                ? accountTypeManager.getAccountInfoForAccount(
+                mCurrentRawContactDelta.getAccountWithDataSet())
+                : accountTypeManager.getAccountInfoForAccount(mPrimaryAccount);
+
+        // Accounts haven't loaded yet or we are editing.
+        if (mAccounts.isEmpty()) {
+            mAccounts.add(account);
+        }
 
         // Get the account information for the primary raw contact delta
         if (isReadOnlyRawContact()) {
@@ -729,9 +748,7 @@
         }
 
         // If we're saving a new contact and there are multiple accounts, add the account selector.
-        final List<AccountWithDataSet> accounts =
-                AccountTypeManager.getInstance(getContext()).getAccounts(true);
-        if (mHasNewContact && !mIsUserProfile && accounts.size() > 1) {
+        if (mHasNewContact && !mIsUserProfile && mAccounts.size() > 1) {
             addAccountSelector(mCurrentRawContactDelta);
         }
     }
@@ -756,11 +773,11 @@
         final OnClickListener clickListener = new OnClickListener() {
             @Override
             public void onClick(View v) {
+                final AccountWithDataSet current = rawContactDelta.getAccountWithDataSet();
+                AccountInfo.sortAccounts(current, mAccounts);
                 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
                 final AccountsListAdapter adapter =
-                        new AccountsListAdapter(getContext(),
-                                AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
-                                mPrimaryAccount);
+                        new AccountsListAdapter(getContext(), mAccounts, current);
                 popup.setWidth(mAccountHeaderContainer.getWidth());
                 popup.setAnchorView(mAccountHeaderContainer);
                 popup.setAdapter(adapter);
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index fa8d6e2..434d10b 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -599,6 +599,9 @@
 
     @Override
     public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) {
+        if (account == null) {
+            return null;
+        }
         final AccountType type = mTypeProvider.getTypeForAccount(account);
         if (type == null) {
             return null;
diff --git a/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java b/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
index b42308d..9eea4d1 100644
--- a/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
+++ b/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
@@ -26,8 +26,11 @@
 
 import com.android.contacts.R;
 import com.android.contacts.model.account.AccountDisplayInfo;
+import com.android.contacts.model.account.AccountInfo;
 import com.android.contacts.model.account.AccountType;
 import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.DeviceLocalAccountType;
+import com.android.contacts.tests.FakeAccountType;
 
 /**
  * Tests {@link EditorUiUtils}.
@@ -73,8 +76,9 @@
     }
 
     public void testGetProfileAccountInfo_NonLocalAccount() {
-        final AccountDisplayInfo account = new AccountDisplayInfo(ACCOUNT, ACCOUNT_NAME,
-                DISPLAY_LABEL, /*icon*/ null, /*isDeviceAccount*/ false);
+        final AccountInfo account = new AccountInfo(new AccountDisplayInfo(ACCOUNT, ACCOUNT_NAME,
+                DISPLAY_LABEL, null, /* isDeviceAccount */ false),
+                new FakeAccountType("com.example.account"));
 
         final String label = EditorUiUtils.getAccountHeaderLabelForMyProfile(getContext(),
                 account);
@@ -87,8 +91,8 @@
 
 
     public void testGetProfileAccountInfo_DeviceLocalAccount() {
-        final AccountDisplayInfo account = new AccountDisplayInfo(ACCOUNT, "Device",
-                "Device", null, true);
+        final AccountInfo account = new AccountInfo(new AccountDisplayInfo(ACCOUNT, "Device",
+                "Device", null, true), new DeviceLocalAccountType(mContext));
 
         final String label = EditorUiUtils.getAccountHeaderLabelForMyProfile(getContext(),
                 account);