Set/get default account to/from CP2 DB.

Test: unit tests.

Bug: 188347310
Change-Id: I9c5f487699662d08f8ff6137ceda08375bd7227c
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index c20330d..7bc7935 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.contacts;
 
+import android.accounts.Account;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -4138,6 +4139,50 @@
     }
 
     /**
+     * Set is_default column for the given account name and account type.
+     *
+     * @param accountName The account name to be set to default.
+     * @param accountType The account type to be set to default.
+     */
+    public void setDefaultAccount(String accountName, String accountType) {
+        SQLiteDatabase db = getWritableDatabase();
+        db.execSQL(
+            "UPDATE " + Tables.ACCOUNTS +
+                " SET " + AccountsColumns.IS_DEFAULT + "=0" +
+                " WHERE " + AccountsColumns.IS_DEFAULT + "=1");
+
+        ContentValues values = new ContentValues();
+        if (!TextUtils.isEmpty(accountName)) {
+            values.put(AccountsColumns.ACCOUNT_NAME, accountName);
+        }
+        if (!TextUtils.isEmpty(accountType)) {
+            values.put(AccountsColumns.ACCOUNT_TYPE, accountType);
+        }
+        values.put(AccountsColumns.IS_DEFAULT, 1);
+        db.insertWithOnConflict(Tables.ACCOUNTS, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+    }
+
+    /**
+     * Return the default account from Accounts table.
+     */
+    public Account getDefaultAccount() {
+        Account defaultAccount = null;
+        try (Cursor c = getReadableDatabase().rawQuery(
+                "SELECT " + AccountsColumns.ACCOUNT_NAME + ","
+                + AccountsColumns.ACCOUNT_TYPE + " FROM " + Tables.ACCOUNTS + " WHERE "
+                + AccountsColumns.IS_DEFAULT + " = 1", null)) {
+            while (c.moveToNext()) {
+                String accountName = c.getString(0);
+                String accountType = c.getString(1);
+                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
+                    defaultAccount = new Account(accountName, accountType);
+                }
+            }
+        }
+        return defaultAccount;
+    }
+
+    /**
      * Update {@link Contacts#IN_VISIBLE_GROUP} for all contacts.
      */
     public void updateAllVisible() {
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 7171240..737b4b5 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -219,6 +219,8 @@
     private static final String WRITE_PERMISSION = "android.permission.WRITE_CONTACTS";
     private static final String MANAGE_SIM_ACCOUNTS_PERMISSION =
             "android.contacts.permission.MANAGE_SIM_ACCOUNTS";
+    private static final String SET_DEFAULT_ACCOUNT_PERMISSION =
+            "android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS";
 
 
     /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK";
@@ -2389,6 +2391,40 @@
             response.putParcelableList(SimContacts.KEY_SIM_ACCOUNTS, simAccounts);
 
             return response;
+        } else if (Settings.QUERY_DEFAULT_ACCOUNT_METHOD.equals(method)) {
+            ContactsPermissions.enforceCallingOrSelfPermission(getContext(), READ_PERMISSION);
+            final Bundle response = new Bundle();
+
+            final Account defaultAccount = mDbHelper.get().getDefaultAccount();
+            response.putParcelable(Settings.KEY_DEFAULT_ACCOUNT, defaultAccount);
+
+            return response;
+        } else if (Settings.SET_DEFAULT_ACCOUNT_METHOD.equals(method)) {
+            ContactsPermissions.enforceCallingOrSelfPermission(getContext(),
+                    SET_DEFAULT_ACCOUNT_PERMISSION);
+            final String accountName = extras.getString(Settings.ACCOUNT_NAME);
+            final String accountType = extras.getString(Settings.ACCOUNT_TYPE);
+            final String dataSet = extras.getString(Settings.DATA_SET);
+
+            if (TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType)) {
+                throw new IllegalArgumentException(
+                        "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE");
+            }
+            if (!TextUtils.isEmpty(dataSet)) {
+                throw new IllegalArgumentException(
+                        "Cannot set default account with non-null data set.");
+            }
+
+            final Bundle response = new Bundle();
+            final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
+            db.beginTransaction();
+            try {
+                mDbHelper.get().setDefaultAccount(accountName, accountType);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            return response;
         }
         return null;
     }
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
index a9867c5..8c060cb 100644
--- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentValues;
 import android.database.ContentObserver;
+import android.accounts.Account;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
@@ -508,4 +509,28 @@
 
         assertEquals(creationTime, dbHelper2.getDatabaseCreationTime());
     }
+
+    public void testGetAndSetDefaultAccount() {
+        Account account = mDbHelper.getDefaultAccount();
+        assertNull(account);
+
+        mDbHelper.setDefaultAccount("a", "b");
+        account = mDbHelper.getDefaultAccount();
+        assertEquals("a", account.name);
+        assertEquals("b", account.type);
+
+        mDbHelper.setDefaultAccount("c", "d");
+        account = mDbHelper.getDefaultAccount();
+        assertEquals("c", account.name);
+        assertEquals("d", account.type);
+
+        mDbHelper.setDefaultAccount(null, null);
+        account = mDbHelper.getDefaultAccount();
+        assertNull(account);
+
+        // invalid account name does nothing.
+        mDbHelper.setDefaultAccount(")--", null);
+        account = mDbHelper.getDefaultAccount();
+        assertNull(account);
+    }
 }
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 0bcab46..dd582d0 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -9124,6 +9124,67 @@
         );
     }
 
+    public void testDefaultAccountSet_throwException() {
+        try {
+            mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD,
+                    null, null);
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        mActor.addPermissions("android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS");
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putString(Settings.ACCOUNT_NAME, "a"); // no account type specified
+            mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD,
+                    null, bundle);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            Bundle bundle = new Bundle();
+            bundle.putString(Settings.ACCOUNT_NAME, "a");
+            bundle.putString(Settings.ACCOUNT_TYPE, "b");
+            bundle.putString(Settings.DATA_SET, "c");
+            mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD,
+                    null, bundle);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testDefaultAccountSetAndQuery() {
+        Bundle response = mResolver.call(ContactsContract.AUTHORITY_URI,
+                Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
+        Account account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT);
+        assertNull(account);
+
+        mActor.addPermissions("android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS");
+        // Set (a, b) account as the default account.
+        Bundle bundle = new Bundle();
+        bundle.putString(Settings.ACCOUNT_NAME, "a");
+        bundle.putString(Settings.ACCOUNT_TYPE, "b");
+        mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD,
+                null, bundle);
+
+        response = mResolver.call(ContactsContract.AUTHORITY_URI,
+                Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
+        account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT);
+        assertEquals("a", account.name);
+        assertEquals("b", account.type);
+
+        // Set NULL account as default account.
+        bundle = new Bundle();
+        mResolver.call(ContactsContract.AUTHORITY_URI, Settings.SET_DEFAULT_ACCOUNT_METHOD,
+            null, bundle);
+
+        response = mResolver.call(ContactsContract.AUTHORITY_URI,
+                Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
+        account = response.getParcelable(Settings.KEY_DEFAULT_ACCOUNT);
+        assertNull(account);
+    }
+
     public void testPinnedPositionsDemoteIllegalArguments() {
         try {
             mResolver.call(ContactsContract.AUTHORITY_URI, PinnedPositions.UNDEMOTE_METHOD,