Merge "Merge Android R"
diff --git a/src/com/android/contacts/drawer/DrawerAdapter.java b/src/com/android/contacts/drawer/DrawerAdapter.java
index 0c8423a..b5a1ea7 100644
--- a/src/com/android/contacts/drawer/DrawerAdapter.java
+++ b/src/com/android/contacts/drawer/DrawerAdapter.java
@@ -271,16 +271,16 @@
             result.setId(item.id);
         }
         final ContactListFilter account = item.account;
+        final AccountDisplayInfo displayableAccount =
+                mAccountDisplayFactory.getAccountDisplayInfoFor(item.account);
         final TextView textView = ((TextView) result.findViewById(R.id.title));
-        textView.setText(account.accountName);
+        textView.setText(displayableAccount.getNameLabel());
         final boolean activated = account.equals(mSelectedAccount)
                 && mSelectedView == ContactsView.ACCOUNT_VIEW;
         textView.setTextAppearance(mActivity, activated
                 ? TYPEFACE_STYLE_ACTIVATE : TYPEFACE_STYLE_INACTIVE);
 
         final ImageView icon = (ImageView) result.findViewById(R.id.icon);
-        final AccountDisplayInfo displayableAccount =
-                mAccountDisplayFactory.getAccountDisplayInfoFor(item.account);
         icon.setScaleType(ImageView.ScaleType.FIT_CENTER);
         icon.setImageDrawable(displayableAccount.getIcon());
 
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 34f9cb2..196e67f 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -405,28 +405,26 @@
 
         ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this);
 
-        if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) {
-            // Observe changes to RAW_CONTACTS so that we will update the list of "Device" accounts
-            // if a new device contact is added.
-            mContext.getContentResolver().registerContentObserver(
-                    ContactsContract.RawContacts.CONTENT_URI, /* notifyDescendents */ true,
-                    new ContentObserver(mMainThreadHandler) {
-                        @Override
-                        public boolean deliverSelfNotifications() {
-                            return true;
-                        }
+        // Observe changes to RAW_CONTACTS so that we will update the list of "Device" accounts
+        // if a new device contact is added or removed.
+        mContext.getContentResolver().registerContentObserver(
+                ContactsContract.RawContacts.CONTENT_URI, /* notifyDescendents */ true,
+                new ContentObserver(mMainThreadHandler) {
+                    @Override
+                    public boolean deliverSelfNotifications() {
+                        return true;
+                    }
 
-                        @Override
-                        public void onChange(boolean selfChange) {
-                            reloadLocalAccounts();
-                        }
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        reloadLocalAccounts();
+                    }
 
-                        @Override
-                        public void onChange(boolean selfChange, Uri uri) {
-                            reloadLocalAccounts();
-                        }
-                    });
-        }
+                    @Override
+                    public void onChange(boolean selfChange, Uri uri) {
+                        reloadLocalAccounts();
+                    }
+                });
         loadAccountTypes();
     }
 
diff --git a/src/com/android/contacts/model/DeviceLocalAccountLocator.java b/src/com/android/contacts/model/DeviceLocalAccountLocator.java
index 4281de9..2b987d3 100644
--- a/src/com/android/contacts/model/DeviceLocalAccountLocator.java
+++ b/src/com/android/contacts/model/DeviceLocalAccountLocator.java
@@ -18,6 +18,8 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract;
 
 import com.android.contacts.Experiments;
 import com.android.contacts.model.account.AccountWithDataSet;
@@ -69,23 +71,25 @@
             return new Cp2DeviceLocalAccountLocator(context.getContentResolver(),
                     ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownTypes);
         } else {
-            return new NexusDeviceAccountLocator(accountManager);
+            return new NexusDeviceAccountLocator(context, accountManager);
         }
     }
 
     /**
      * On Nexus the "device" account uses "null" values for the account name and type columns
      *
-     * <p>However, the focus sync adapter automatically migrates contacts from this null
-     * account to a Google account if one exists. Hence, the device account should be returned
-     * only when there is no Google Account added
+     * <p>However, the focus sync adapter migrates contacts from this null account to a Google
+     * account if one exists. Hence, the device account should be returned only when there is no
+     * Google Account added or when there already exists contacts in the null account.
      * </p>
      */
     public static class NexusDeviceAccountLocator extends DeviceLocalAccountLocator {
-
+        private final Context mContext;
         private final AccountManager mAccountManager;
 
-        public NexusDeviceAccountLocator(AccountManager accountManager) {
+
+        public NexusDeviceAccountLocator(Context context, AccountManager accountManager) {
+            mContext = context;
             mAccountManager = accountManager;
         }
 
@@ -95,7 +99,7 @@
             final Account[] accounts = mAccountManager
                     .getAccountsByType(GoogleAccountType.ACCOUNT_TYPE);
 
-            if (accounts.length > 0) {
+            if (accounts.length > 0 && !AccountWithDataSet.getNullAccount().hasData(mContext)) {
                 return Collections.emptyList();
             } else {
                 return Collections.singletonList(AccountWithDataSet.getNullAccount());
diff --git a/tests/Android.bp b/tests/Android.bp
index 7754fd4..2e1d47b 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -22,4 +22,6 @@
         "android.test.base.stubs",
         "android.test.mock.stubs",
     ],
+
+    test_suites: ["general-tests"],
 }
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
new file mode 100644
index 0000000..5665490
--- /dev/null
+++ b/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Tests for Contacts.">
+  <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+    <option name="cleanup-apks" value="true" />
+    <option name="test-file-name" value="ContactsTests.apk" />
+  </target_preparer>
+
+  <option name="test-suite-tag" value="apct" />
+  <option name="test-tag" value="ContactsTests" />
+  <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+    <option name="package" value="com.android.contacts.tests" />
+    <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+    <option name="hidden-api-checks" value="false"/>
+  </test>
+</configuration>
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..43d905c
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,13 @@
+# Running tests
+
+Build and install Contacts.apk
+
+Grant Contacts permissions to Contacts.apk
+
+Run
+```shell
+$ atest ContactsTests
+```
+
+More information can be found at
+https://source.android.com/compatibility/tests/development/atest
diff --git a/tests/src/com/android/contacts/activities/SimImportActivityTest.java b/tests/src/com/android/contacts/activities/SimImportActivityTest.java
index 9c90426..7069ef1 100644
--- a/tests/src/com/android/contacts/activities/SimImportActivityTest.java
+++ b/tests/src/com/android/contacts/activities/SimImportActivityTest.java
@@ -327,9 +327,9 @@
         mDevice.findObject(By.textContains(targetAccount.name)).click();
         mDevice.waitForIdle();
 
-        assertTrue(mDevice.wait(Until.hasObject(By.text("Import One").checked(false).enabled(false)), TIMEOUT));
-        assertTrue(mDevice.hasObject(By.text("Import Three").checked(false).enabled(false)));
-        assertTrue(mDevice.hasObject(By.text("Import Six").checked(false).enabled(false)));
+        assertTrue(mDevice.wait(Until.hasObject(By.text("Import One").checked(false)), TIMEOUT));
+        assertTrue(mDevice.hasObject(By.text("Import Three").checked(false)));
+        assertTrue(mDevice.hasObject(By.text("Import Six").checked(false)));
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             contactsProviderClient.close();
diff --git a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
index 982517b..dfcb390 100644
--- a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
+++ b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
@@ -96,7 +96,7 @@
     }
 
     public void testGetDefaultAccount_NoAccounts_DefaultPreferenceSet() {
-        when(mPrefs.getString(Mockito.anyString(), Mockito.anyString())).thenReturn(
+        when(mPrefs.getString(Mockito.anyString(), Mockito.any())).thenReturn(
                 getDefaultAccountPreference("name1", GoogleAccountType.ACCOUNT_TYPE));
         assertNull(getDefaultGoogleAccountName());
     }
@@ -108,21 +108,21 @@
 
     public void testGetDefaultAccount_DefaultAccountPreferenceSet() {
         when(mAccountManager.getAccountsByType(Mockito.anyString())).thenReturn(ACCOUNTS);
-        when(mPrefs.getString(Mockito.anyString(), Mockito.anyString())).thenReturn(
+        when(mPrefs.getString(Mockito.anyString(), Mockito.any())).thenReturn(
                 getDefaultAccountPreference("name2", GoogleAccountType.ACCOUNT_TYPE));
         assertEquals("name2", getDefaultGoogleAccountName());
     }
 
     public void testGetDefaultAccount_DefaultAccountPreferenceSet_NonGoogleAccountType() {
         when(mAccountManager.getAccountsByType(Mockito.anyString())).thenReturn(ACCOUNTS);
-        when(mPrefs.getString(Mockito.anyString(), Mockito.anyString())).thenReturn(
+        when(mPrefs.getString(Mockito.anyString(), Mockito.any())).thenReturn(
                 getDefaultAccountPreference("name3", "type3"));
         assertEquals("name1", getDefaultGoogleAccountName());
     }
 
     public void testGetDefaultAccount_DefaultAccountPreferenceSet_UnknownName() {
         when(mAccountManager.getAccountsByType(Mockito.anyString())).thenReturn(ACCOUNTS);
-        when(mPrefs.getString(Mockito.anyString(), Mockito.anyString())).thenReturn(
+        when(mPrefs.getString(Mockito.anyString(), Mockito.any())).thenReturn(
                 getDefaultAccountPreference("name4",GoogleAccountType.ACCOUNT_TYPE));
         assertEquals("name1", getDefaultGoogleAccountName());
     }
diff --git a/tests/src/com/android/contacts/preference/ContactsPreferencesTest.java b/tests/src/com/android/contacts/preference/ContactsPreferencesTest.java
index 998f385..d7f34ee 100644
--- a/tests/src/com/android/contacts/preference/ContactsPreferencesTest.java
+++ b/tests/src/com/android/contacts/preference/ContactsPreferencesTest.java
@@ -56,7 +56,7 @@
         Mockito.when(mResources.getString(Mockito.anyInt()))
                 .thenReturn(ACCOUNT_KEY); // contact_editor_default_account_key
 
-        Mockito.when(mContext.getSharedPreferences(Mockito.anyString(), Mockito.anyInt()))
+        Mockito.when(mContext.getSharedPreferences(Mockito.any(), Mockito.anyInt()))
                 .thenReturn(mSharedPreferences);
         Mockito.when(mSharedPreferences.contains(ContactsPreferences.SORT_ORDER_KEY))
                 .thenReturn(true);
@@ -184,7 +184,7 @@
         mContactsPreferences = new ContactsPreferences(mContext,
                 /* isDefaultAccountUserChangeable */ true);
 
-        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.any()))
                 .thenReturn(new AccountWithDataSet("name1", "type1", "dataset1").stringify(),
                         new AccountWithDataSet("name2", "type2", "dataset2").stringify());
 
@@ -199,7 +199,7 @@
     public void testShouldShowAccountChangedNotificationIfAccountNotSaved() {
         mContactsPreferences = new ContactsPreferences(mContext,
                 /* isDefaultAccountUserChangeable */ true);
-        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.any()))
                 .thenReturn(null);
 
         assertTrue("Should prompt to change default if no default is saved",
@@ -211,7 +211,7 @@
     public void testShouldShowAccountChangedNotification() {
         mContactsPreferences = new ContactsPreferences(mContext,
                 /* isDefaultAccountUserChangeable */ true);
-        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.any()))
                 .thenReturn(new AccountWithDataSet("name", "type", "dataset").stringify());
 
         assertFalse("Should not prompt to change default if current default exists",
@@ -228,7 +228,7 @@
     public void testShouldShowAccountChangedNotificationWhenThereIsOneAccount() {
         mContactsPreferences = new ContactsPreferences(mContext,
                 /* isDefaultAccountUserChangeable */ true);
-        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+        Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.any()))
                 .thenReturn(null);
 
         // Normally we would prompt because there is no default set but if there is just one
diff --git a/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java b/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java
index 993d0b7..a08bff9 100644
--- a/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java
+++ b/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java
@@ -23,8 +23,10 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import androidx.annotation.Nullable;
@@ -203,4 +205,8 @@
             throw new RuntimeException(e);
         }
     }
+
+    public IBinder getIContentProviderBinder() {
+        return new Binder();
+    }
 }