Use CP2 for default account setting in AOSP.
1) read the setting from CP2.
2) add an activity to handle the intent to set the setting
when it's the preloaded contacts app.
Test: manual tests.
Bug: 213629089
Change-Id: Ib8338e9a3c4531eb642d1ee6c6a3cea2546a2dc7
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f47d42a4..c424c80 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -262,6 +262,17 @@
android:theme="@style/ContactsPreferencesTheme"/>
<activity
+ android:name=".preference.SetDefaultAccountActivity"
+ android:exported="true"
+ android:theme="@style/BackgroundOnlyTheme"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.provider.action.SET_DEFAULT_ACCOUNT"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity
android:name=".activities.LicenseActivity"
android:exported="true"
android:label="@string/activity_title_licenses"
diff --git a/res/xml/preference_display_options.xml b/res/xml/preference_display_options.xml
index c969cd2..9987250 100644
--- a/res/xml/preference_display_options.xml
+++ b/res/xml/preference_display_options.xml
@@ -26,7 +26,7 @@
android:title="@string/settings_accounts">
</Preference>
- <com.android.contacts.preference.DefaultAccountPreference
+ <Preference
android:icon="@null"
android:key="defaultAccount"
android:title="@string/default_editor_account"
diff --git a/src/com/android/contacts/preference/ContactsPreferences.java b/src/com/android/contacts/preference/ContactsPreferences.java
index e1a58d3..e5f0cda 100644
--- a/src/com/android/contacts/preference/ContactsPreferences.java
+++ b/src/com/android/contacts/preference/ContactsPreferences.java
@@ -16,20 +16,29 @@
package com.android.contacts.preference;
+import static android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS;
+
+import android.accounts.Account;
+import android.annotation.SuppressLint;
import android.app.backup.BackupManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Handler;
import android.os.Looper;
+import android.os.StrictMode;
import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
import com.android.contacts.R;
import com.android.contacts.model.account.AccountWithDataSet;
@@ -209,23 +218,45 @@
return mIsDefaultAccountUserChangeable;
}
+ @SuppressLint("NewApi")
public AccountWithDataSet getDefaultAccount() {
if (!isDefaultAccountUserChangeable()) {
return mDefaultAccount;
}
if (mDefaultAccount == null) {
- final String accountString = mPreferences
- .getString(mDefaultAccountKey, null);
- if (!TextUtils.isEmpty(accountString)) {
- mDefaultAccount = AccountWithDataSet.unstringify(accountString);
+ Account cp2DefaultAccount = null;
+ if (BuildCompat.isAtLeastT()) {
+ cp2DefaultAccount = getDefaultAccountFromCp2();
}
+
+ mDefaultAccount = cp2DefaultAccount == null
+ ? AccountWithDataSet.getNullAccount()
+ : new AccountWithDataSet(cp2DefaultAccount.name, cp2DefaultAccount.type, null);
}
return mDefaultAccount;
}
+ @RequiresApi(33)
+ private Account getDefaultAccountFromCp2() {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder(oldPolicy)
+ .permitDiskReads()
+ .build());
+ try {
+ return ContactsContract.Settings.getDefaultAccount(
+ mContext.getContentResolver());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
public void clearDefaultAccount() {
- mDefaultAccount = null;
- mPreferences.edit().remove(mDefaultAccountKey).commit();
+ if (mContext.checkSelfPermission(SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
+ == PackageManager.PERMISSION_GRANTED) {
+ mDefaultAccount = null;
+ setDefaultAccountToCp2(null);
+ }
}
public void setDefaultAccount(@NonNull AccountWithDataSet accountWithDataSet) {
@@ -233,12 +264,30 @@
throw new IllegalArgumentException(
"argument should not be null");
}
- mDefaultAccount = accountWithDataSet;
- mPreferences.edit().putString(mDefaultAccountKey, accountWithDataSet.stringify()).commit();
+ if (mContext.checkSelfPermission(SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
+ == PackageManager.PERMISSION_GRANTED) {
+ mDefaultAccount = accountWithDataSet;
+ setDefaultAccountToCp2(accountWithDataSet);
+ }
+ }
+
+ private void setDefaultAccountToCp2(AccountWithDataSet accountWithDataSet) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder(oldPolicy)
+ .permitDiskWrites()
+ .permitDiskReads()
+ .build());
+ try {
+ ContactsContract.Settings.setDefaultAccount(mContext.getContentResolver(),
+ accountWithDataSet == null ? null : accountWithDataSet.getAccountOrNull());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
}
public boolean isDefaultAccountSet() {
- return mDefaultAccount != null || mPreferences.contains(mDefaultAccountKey);
+ return mDefaultAccount != null;
}
/**
@@ -391,6 +440,15 @@
setDefaultAccount(accountWithDataSet);
}
}
+
+ if (mPreferences.contains(mDefaultAccountKey) && getDefaultAccount() == null) {
+ String defaultAccount = mPreferences.getString(mDefaultAccountKey, null);
+ if (!TextUtils.isEmpty(defaultAccount)) {
+ final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(
+ defaultAccount);
+ setDefaultAccount(accountWithDataSet);
+ }
+ }
}
}
diff --git a/src/com/android/contacts/preference/DefaultAccountPreference.java b/src/com/android/contacts/preference/DefaultAccountPreference.java
deleted file mode 100644
index d43b8d5..0000000
--- a/src/com/android/contacts/preference/DefaultAccountPreference.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 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
- */
-
-package com.android.contacts.preference;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.preference.DialogPreference;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.android.contacts.model.account.AccountInfo;
-import com.android.contacts.model.account.AccountWithDataSet;
-import com.android.contacts.util.AccountsListAdapter;
-
-import java.util.List;
-
-public class DefaultAccountPreference extends DialogPreference {
- private ContactsPreferences mPreferences;
- private AccountsListAdapter mListAdapter;
- private List<AccountInfo> mAccounts;
- private int mChosenIndex = -1;
-
- public DefaultAccountPreference(Context context) {
- super(context);
- prepare();
- }
-
- public DefaultAccountPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- prepare();
- }
-
- public void setAccounts(List<AccountInfo> accounts) {
- mAccounts = accounts;
- if (mListAdapter != null) {
- mListAdapter.setAccounts(accounts, null);
- notifyChanged();
- }
- }
-
- @Override
- protected View onCreateDialogView() {
- prepare();
- return super.onCreateDialogView();
- }
-
- private void prepare() {
- mPreferences = new ContactsPreferences(getContext());
- mListAdapter = new AccountsListAdapter(getContext());
- if (mAccounts != null) {
- mListAdapter.setAccounts(mAccounts, null);
- }
- }
-
- @Override
- protected boolean shouldPersist() {
- return false; // This preference takes care of its own storage
- }
-
- @Override
- public CharSequence getSummary() {
- final AccountWithDataSet defaultAccount = mPreferences.getDefaultAccount();
- if (defaultAccount == null || mAccounts == null ||
- !AccountInfo.contains(mAccounts, defaultAccount)) {
- return null;
- } else {
- return AccountInfo.getAccount(mAccounts, defaultAccount).getNameLabel();
- }
- }
-
- @Override
- protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
- super.onPrepareDialogBuilder(builder);
- // UX recommendation is not to show buttons on such lists.
- builder.setNegativeButton(null, null);
- builder.setPositiveButton(null, null);
- builder.setAdapter(mListAdapter, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mChosenIndex = which;
- }
- });
- }
-
- @Override
- protected void onDialogClosed(boolean positiveResult) {
- final AccountWithDataSet currentDefault = mPreferences.getDefaultAccount();
-
- if (mChosenIndex != -1) {
- final AccountWithDataSet chosenAccount = mListAdapter.getItem(mChosenIndex);
- if (!chosenAccount.equals(currentDefault)) {
- mPreferences.setDefaultAccount(chosenAccount);
- notifyChanged();
- }
- } // else the user dismissed this dialog so leave the preference unchanged.
- }
-}
diff --git a/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
index fd358aa..7097be3 100644
--- a/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
+++ b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
@@ -16,6 +16,7 @@
package com.android.contacts.preference;
+import android.accounts.Account;
import android.app.Activity;
import android.app.LoaderManager;
import android.content.BroadcastReceiver;
@@ -25,17 +26,21 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.icu.text.MessageFormat;
import android.net.Uri;
import android.os.Bundle;
+import android.os.StrictMode;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.BlockedNumberContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.DisplayNameSources;
import android.provider.ContactsContract.Profile;
+import android.provider.ContactsContract.Settings;
import com.google.android.material.snackbar.Snackbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.telecom.TelecomManager;
@@ -59,11 +64,13 @@
import com.android.contacts.logging.ScreenEvent.ScreenType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.account.AccountInfo;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.model.account.AccountsLoader;
import com.android.contacts.util.AccountFilterUtil;
import com.android.contacts.util.ImplicitIntentsUtil;
import com.android.contactsbind.HelpUtils;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -76,6 +83,7 @@
implements Preference.OnPreferenceClickListener, AccountsLoader.AccountsListener {
private static final int REQUEST_CODE_CUSTOM_CONTACTS_FILTER = 0;
+ private static final int REQUEST_CODE_SET_DEFAULT_ACCOUNT_CP2 = 1;
private static final String ARG_CONTACTS_AVAILABLE = "are_contacts_available";
private static final String ARG_NEW_LOCAL_PROFILE = "new_local_profile";
@@ -147,6 +155,8 @@
private ViewGroup mRootView;
private SaveServiceResultListener mSaveServiceListener;
+ private List<AccountInfo> accounts = Collections.emptyList();
+
private final LoaderManager.LoaderCallbacks<Cursor> mProfileLoaderListener =
new LoaderManager.LoaderCallbacks<Cursor>() {
@@ -249,6 +259,12 @@
customFilterPreference.setOnPreferenceClickListener(this);
setCustomContactsFilterSummary();
}
+
+ final Preference defaultAccountPreference = findPreference(KEY_DEFAULT_ACCOUNT);
+ if (defaultAccountPreference != null) {
+ defaultAccountPreference.setOnPreferenceClickListener(this);
+ defaultAccountPreference.setSummary(getDefaultAccountSummary());
+ }
}
@Override
@@ -314,9 +330,10 @@
@Override
public void onAccountsLoaded(List<AccountInfo> accounts) {
// Hide accounts preferences if no writable accounts exist
- final DefaultAccountPreference preference =
- (DefaultAccountPreference) findPreference(KEY_DEFAULT_ACCOUNT);
- preference.setAccounts(accounts);
+ this.accounts = accounts;
+ final Preference defaultAccountPreference =
+ findPreference(KEY_DEFAULT_ACCOUNT);
+ defaultAccountPreference.setSummary(getDefaultAccountSummary());
}
@Override
@@ -384,6 +401,13 @@
ContactListFilterController.getInstance(getContext()).getFilter();
AccountFilterUtil.startAccountFilterActivityForResult(
this, REQUEST_CODE_CUSTOM_CONTACTS_FILTER, filter);
+ } else if (KEY_DEFAULT_ACCOUNT.equals(prefKey)) {
+ String packageName = getSetDefaultAccountActivityPackage();
+ Intent intent = new Intent(Settings.ACTION_SET_DEFAULT_ACCOUNT);
+ if (packageName != null) {
+ intent.setPackage(packageName);
+ startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_ACCOUNT_CP2);
+ }
}
return false;
}
@@ -395,6 +419,12 @@
AccountFilterUtil.handleAccountFilterResult(
ContactListFilterController.getInstance(getContext()), resultCode, data);
setCustomContactsFilterSummary();
+ } else if (requestCode == REQUEST_CODE_SET_DEFAULT_ACCOUNT_CP2
+ && resultCode == Activity.RESULT_OK) {
+ final Preference defaultAccountPreference = findPreference(KEY_DEFAULT_ACCOUNT);
+ if (defaultAccountPreference != null) {
+ defaultAccountPreference.setSummary(getDefaultAccountSummary());
+ }
} else {
super.onActivityResult(requestCode, resultCode, data);
}
@@ -418,6 +448,34 @@
}
}
+ private CharSequence getDefaultAccountSummary() {
+ ContactsPreferences preferences = new ContactsPreferences(getContext());
+ AccountWithDataSet defaultAccountWithDataSet = preferences.getDefaultAccount();
+ AccountInfo defaultAccountInfo = AccountInfo.getAccount(
+ accounts, defaultAccountWithDataSet);
+ if (defaultAccountInfo != null) {
+ return defaultAccountInfo.getNameLabel();
+ } else {
+ return null;
+ }
+ }
+
+ private String getSetDefaultAccountActivityPackage() {
+ // Only preloaded Contacts App has the permission to call setDefaultAccount.
+ Intent intent = new Intent(Settings.ACTION_SET_DEFAULT_ACCOUNT);
+ PackageManager packageManager = getContext().getPackageManager();
+ List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ if (packageManager.checkPermission(
+ android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS, packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return packageName;
+ }
+ }
+ return null;
+ }
+
private class SaveServiceResultListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/src/com/android/contacts/preference/SetDefaultAccountActivity.java b/src/com/android/contacts/preference/SetDefaultAccountActivity.java
new file mode 100644
index 0000000..b636ac3
--- /dev/null
+++ b/src/com/android/contacts/preference/SetDefaultAccountActivity.java
@@ -0,0 +1,35 @@
+package com.android.contacts.preference;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.contacts.R;
+import com.android.contacts.editor.SelectAccountDialogFragment;
+import com.android.contacts.model.AccountTypeManager.AccountFilter;
+import com.android.contacts.model.account.AccountWithDataSet;
+
+/** Activity to open a dialog for default account selection. */
+public final class SetDefaultAccountActivity extends Activity
+ implements SelectAccountDialogFragment.Listener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SelectAccountDialogFragment.show(getFragmentManager(),
+ R.string.default_editor_account, AccountFilter.CONTACTS_WRITABLE, null);
+ }
+
+ @Override
+ public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
+ ContactsPreferences preferences = new ContactsPreferences(this);
+ preferences.setDefaultAccount(account);
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+
+ @Override
+ public void onAccountSelectorCancelled() {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ }
+}