From b279b1c0251870a1bb385c8c93ed9ba1792a2790 Mon Sep 17 00:00:00 2001 From: Emily Chuang Date: Thu, 12 Apr 2018 10:12:28 +0800 Subject: Migrate ChooseAccountActivity to DashboardFragment - Build a controller to generate/manage a list of preferences. - Move some logics to the controller and add tests. - Rename to ChooseAccountFragment. Bug: 73899467 Test: make RunSettingsRoboTests -j atest UniquePreferenceTest SettingsGatewayTest Change-Id: Id2906c4b922ef159d08c803b976671264c54665f --- AndroidManifest.xml | 2 +- res/xml/add_account_settings.xml | 9 +- .../settings/accounts/ChooseAccountActivity.java | 322 --------------------- .../settings/accounts/ChooseAccountFragment.java | 107 +++++++ .../ChooseAccountPreferenceController.java | 287 ++++++++++++++++++ .../EnterpriseDisclosurePreferenceController.java | 79 +++++ .../android/settings/accounts/ProviderEntry.java | 47 +++ .../settings/core/gateway/SettingsGateway.java | 4 +- .../assets/grandfather_not_implementing_indexable | 1 - .../ChooseAccountPreferenceControllerTest.java | 205 +++++++++++++ ...terpriseDisclosurePreferenceControllerTest.java | 99 +++++++ .../testutils/shadow/ShadowAccountManager.java | 18 +- .../shadow/ShadowRestrictedLockUtils.java | 75 +++-- 13 files changed, 907 insertions(+), 348 deletions(-) delete mode 100644 src/com/android/settings/accounts/ChooseAccountActivity.java create mode 100644 src/com/android/settings/accounts/ChooseAccountFragment.java create mode 100644 src/com/android/settings/accounts/ChooseAccountPreferenceController.java create mode 100644 src/com/android/settings/accounts/EnterpriseDisclosurePreferenceController.java create mode 100644 src/com/android/settings/accounts/ProviderEntry.java create mode 100644 tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceControllerTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 69416a7223..5a0f18192f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2341,7 +2341,7 @@ android:label="@string/header_add_an_account" android:configChanges="orientation|keyboardHidden|screenSize"> + android:value="com.android.settings.accounts.ChooseAccountFragment" /> - - - + diff --git a/src/com/android/settings/accounts/ChooseAccountActivity.java b/src/com/android/settings/accounts/ChooseAccountActivity.java deleted file mode 100644 index 35f51afa80..0000000000 --- a/src/com/android/settings/accounts/ChooseAccountActivity.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2010 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.settings.accounts; - -import static android.app.Activity.RESULT_CANCELED; -import static android.app.Activity.RESULT_OK; -import static android.content.Intent.EXTRA_USER; - -import android.accounts.AccountManager; -import android.accounts.AuthenticatorDescription; -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.SyncAdapterType; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.UserHandle; -import android.os.UserManager; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import android.util.Log; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.CharSequences; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; -import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; -import com.android.settingslib.widget.FooterPreference; -import com.android.settingslib.widget.FooterPreferenceMixin; - -import com.google.android.collect.Maps; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; - -/** - * Activity asking a user to select an account to be set up. - * - * An extra {@link UserHandle} can be specified in the intent as {@link EXTRA_USER}, if the user for - * which the action needs to be performed is different to the one the Settings App will run in. - */ -public class ChooseAccountActivity extends SettingsPreferenceFragment { - - private static final String TAG = "ChooseAccountActivity"; - - private EnterprisePrivacyFeatureProvider mFeatureProvider; - private FooterPreference mEnterpriseDisclosurePreference = null; - - private String[] mAuthorities; - private PreferenceGroup mAddAccountGroup; - private final ArrayList mProviderList = new ArrayList(); - public HashSet mAccountTypesFilter; - private AuthenticatorDescription[] mAuthDescs; - private HashMap> mAccountTypeToAuthorities = null; - private Map mTypeToAuthDescription - = new HashMap(); - // The UserHandle of the user we are choosing an account for - private UserHandle mUserHandle; - private UserManager mUm; - - private static class ProviderEntry implements Comparable { - private final CharSequence name; - private final String type; - ProviderEntry(CharSequence providerName, String accountType) { - name = providerName; - type = accountType; - } - - public int compareTo(ProviderEntry another) { - if (name == null) { - return -1; - } - if (another.name == null) { - return +1; - } - return CharSequences.compareToIgnoreCase(name, another.name); - } - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY; - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - final Activity activity = getActivity(); - mFeatureProvider = FeatureFactory.getFactory(activity) - .getEnterprisePrivacyFeatureProvider(activity); - - addPreferencesFromResource(R.xml.add_account_settings); - mAuthorities = getIntent().getStringArrayExtra( - AccountPreferenceBase.AUTHORITIES_FILTER_KEY); - String[] accountTypesFilter = getIntent().getStringArrayExtra( - AccountPreferenceBase.ACCOUNT_TYPES_FILTER_KEY); - if (accountTypesFilter != null) { - mAccountTypesFilter = new HashSet(); - for (String accountType : accountTypesFilter) { - mAccountTypesFilter.add(accountType); - } - } - mAddAccountGroup = getPreferenceScreen(); - mUm = UserManager.get(getContext()); - mUserHandle = Utils.getSecureTargetUser(getActivity().getActivityToken(), mUm, - null /* arguments */, getIntent().getExtras()); - updateAuthDescriptions(); - } - - /** - * Updates provider icons. Subclasses should call this in onCreate() - * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). - */ - private void updateAuthDescriptions() { - mAuthDescs = AccountManager.get(getContext()).getAuthenticatorTypesAsUser( - mUserHandle.getIdentifier()); - for (int i = 0; i < mAuthDescs.length; i++) { - mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); - } - onAuthDescriptionsUpdated(); - } - - private void onAuthDescriptionsUpdated() { - // Create list of providers to show on preference screen - for (int i = 0; i < mAuthDescs.length; i++) { - String accountType = mAuthDescs[i].type; - CharSequence providerName = getLabelForType(accountType); - - // Skip preferences for authorities not specified. If no authorities specified, - // then include them all. - ArrayList accountAuths = getAuthoritiesForAccountType(accountType); - boolean addAccountPref = true; - if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) { - addAccountPref = false; - for (int k = 0; k < mAuthorities.length; k++) { - if (accountAuths.contains(mAuthorities[k])) { - addAccountPref = true; - break; - } - } - } - if (addAccountPref && mAccountTypesFilter != null - && !mAccountTypesFilter.contains(accountType)) { - addAccountPref = false; - } - if (addAccountPref) { - mProviderList.add(new ProviderEntry(providerName, accountType)); - } else { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need"); - } - } - } - - final Context context = getPreferenceScreen().getContext(); - if (mProviderList.size() == 1) { - // There's only one provider that matches. If it is disabled by admin show the - // support dialog otherwise run it. - EnforcedAdmin admin = RestrictedLockUtils.checkIfAccountManagementDisabled( - context, mProviderList.get(0).type, mUserHandle.getIdentifier()); - if (admin != null) { - setResult(RESULT_CANCELED, RestrictedLockUtils.getShowAdminSupportDetailsIntent( - context, admin)); - finish(); - } else { - finishWithAccountType(mProviderList.get(0).type); - } - } else if (mProviderList.size() > 0) { - Collections.sort(mProviderList); - mAddAccountGroup.removeAll(); - for (ProviderEntry pref : mProviderList) { - Drawable drawable = getDrawableForType(pref.type); - ProviderPreference p = new ProviderPreference(getPreferenceScreen().getContext(), - pref.type, drawable, pref.name); - p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier()); - mAddAccountGroup.addPreference(p); - } - addEnterpriseDisclosure(); - } else { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - final StringBuilder auths = new StringBuilder(); - for (String a : mAuthorities) { - auths.append(a); - auths.append(' '); - } - Log.v(TAG, "No providers found for authorities: " + auths); - } - setResult(RESULT_CANCELED); - finish(); - } - } - - private void addEnterpriseDisclosure() { - final CharSequence disclosure = mFeatureProvider.getDeviceOwnerDisclosure(); - if (disclosure == null) { - return; - } - if (mEnterpriseDisclosurePreference == null) { - mEnterpriseDisclosurePreference = mFooterPreferenceMixin.createFooterPreference(); - mEnterpriseDisclosurePreference.setSelectable(false); - } - mEnterpriseDisclosurePreference.setTitle(disclosure); - mAddAccountGroup.addPreference(mEnterpriseDisclosurePreference); - } - - public ArrayList getAuthoritiesForAccountType(String type) { - if (mAccountTypeToAuthorities == null) { - mAccountTypeToAuthorities = Maps.newHashMap(); - SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser( - mUserHandle.getIdentifier()); - for (int i = 0, n = syncAdapters.length; i < n; i++) { - final SyncAdapterType sa = syncAdapters[i]; - ArrayList authorities = mAccountTypeToAuthorities.get(sa.accountType); - if (authorities == null) { - authorities = new ArrayList(); - mAccountTypeToAuthorities.put(sa.accountType, authorities); - } - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, "added authority " + sa.authority + " to accountType " - + sa.accountType); - } - authorities.add(sa.authority); - } - } - return mAccountTypeToAuthorities.get(type); - } - - /** - * Gets an icon associated with a particular account type. If none found, return null. - * @param accountType the type of account - * @return a drawable for the icon or a default icon returned by - * {@link PackageManager#getDefaultActivityIcon} if one cannot be found. - */ - protected Drawable getDrawableForType(final String accountType) { - Drawable icon = null; - if (mTypeToAuthDescription.containsKey(accountType)) { - try { - AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); - Context authContext = getActivity() - .createPackageContextAsUser(desc.packageName, 0, mUserHandle); - icon = getPackageManager().getUserBadgedIcon( - authContext.getDrawable(desc.iconId), mUserHandle); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "No icon name for account type " + accountType); - } catch (Resources.NotFoundException e) { - Log.w(TAG, "No icon resource for account type " + accountType); - } - } - if (icon != null) { - return icon; - } else { - return getPackageManager().getDefaultActivityIcon(); - } - } - - /** - * Gets the label associated with a particular account type. If none found, return null. - * @param accountType the type of account - * @return a CharSequence for the label or null if one cannot be found. - */ - protected CharSequence getLabelForType(final String accountType) { - CharSequence label = null; - if (mTypeToAuthDescription.containsKey(accountType)) { - try { - AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); - Context authContext = getActivity() - .createPackageContextAsUser(desc.packageName, 0, mUserHandle); - label = authContext.getResources().getText(desc.labelId); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "No label name for account type " + accountType); - } catch (Resources.NotFoundException e) { - Log.w(TAG, "No label resource for account type " + accountType); - } - } - return label; - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - if (preference instanceof ProviderPreference) { - ProviderPreference pref = (ProviderPreference) preference; - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Attempting to add account of type " + pref.getAccountType()); - } - finishWithAccountType(pref.getAccountType()); - } - return true; - } - - private void finishWithAccountType(String accountType) { - Intent intent = new Intent(); - intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType); - intent.putExtra(EXTRA_USER, mUserHandle); - setResult(RESULT_OK, intent); - finish(); - } -} diff --git a/src/com/android/settings/accounts/ChooseAccountFragment.java b/src/com/android/settings/accounts/ChooseAccountFragment.java new file mode 100644 index 0000000000..98b9ee6c5e --- /dev/null +++ b/src/com/android/settings/accounts/ChooseAccountFragment.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Activity asking a user to select an account to be set up. + */ +@SearchIndexable +public class ChooseAccountFragment extends DashboardFragment { + + private static final String TAG = "ChooseAccountFragment"; + + @Override + public int getMetricsCategory() { + return MetricsEvent.ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + final String[] authorities = getIntent().getStringArrayExtra( + AccountPreferenceBase.AUTHORITIES_FILTER_KEY); + final String[] accountTypesFilter = getIntent().getStringArrayExtra( + AccountPreferenceBase.ACCOUNT_TYPES_FILTER_KEY); + final UserManager userManager = UserManager.get(getContext()); + final UserHandle userHandle = Utils.getSecureTargetUser(getActivity().getActivityToken(), + userManager, null /* arguments */, getIntent().getExtras()); + + use(ChooseAccountPreferenceController.class).initialize(authorities, accountTypesFilter, + userHandle, getActivity()); + use(EnterpriseDisclosurePreferenceController.class).setFooterPreferenceMixin( + mFooterPreferenceMixin); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.add_account_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildControllers(context); + } + + private static List buildControllers(Context context) { + final List controllers = new ArrayList<>(); + controllers.add(new EnterpriseDisclosurePreferenceController(context)); + return controllers; + } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.add_account_settings; + result.add(sir); + return result; + } + + @Override + public List createPreferenceControllers( + Context context) { + return buildControllers(context); + } + }; +} diff --git a/src/com/android/settings/accounts/ChooseAccountPreferenceController.java b/src/com/android/settings/accounts/ChooseAccountPreferenceController.java new file mode 100644 index 0000000000..ded204bde1 --- /dev/null +++ b/src/com/android/settings/accounts/ChooseAccountPreferenceController.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import static android.app.Activity.RESULT_CANCELED; +import static android.app.Activity.RESULT_OK; +import static android.content.Intent.EXTRA_USER; + +import android.accounts.AccountManager; +import android.accounts.AuthenticatorDescription; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.SyncAdapterType; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.util.Log; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.RestrictedLockUtils; + +import com.google.android.collect.Maps; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +/** + * An extra {@link UserHandle} can be specified in the intent as {@link EXTRA_USER}, if the user for + * which the action needs to be performed is different to the one the Settings App will run in. + */ +public class ChooseAccountPreferenceController extends BasePreferenceController { + + private static final String TAG = "ChooseAccountPrefCtrler"; + + private final List mProviderList; + private final Map mTypeToAuthDescription; + + private String[] mAuthorities; + private Set mAccountTypesFilter; + private AuthenticatorDescription[] mAuthDescs; + private Map> mAccountTypeToAuthorities; + // The UserHandle of the user we are choosing an account for + private UserHandle mUserHandle; + private Activity mActivity; + private PreferenceScreen mScreen; + + public ChooseAccountPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + + mProviderList = new ArrayList<>(); + mTypeToAuthDescription = new HashMap<>(); + } + + public void initialize(String[] authorities, String[] accountTypesFilter, UserHandle userHandle, + Activity activity) { + mActivity = activity; + mAuthorities = authorities; + mUserHandle = userHandle; + + if (accountTypesFilter != null) { + mAccountTypesFilter = new HashSet<>(); + for (String accountType : accountTypesFilter) { + mAccountTypesFilter.add(accountType); + } + } + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mScreen = screen; + updateAuthDescriptions(); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!(preference instanceof ProviderPreference)) { + return false; + } + + ProviderPreference pref = (ProviderPreference) preference; + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Attempting to add account of type " + pref.getAccountType()); + } + finishWithAccountType(pref.getAccountType()); + return true; + } + + /** + * Updates provider icons. Subclasses should call this in onCreate() + * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). + */ + private void updateAuthDescriptions() { + mAuthDescs = AccountManager.get(mContext).getAuthenticatorTypesAsUser( + mUserHandle.getIdentifier()); + for (int i = 0; i < mAuthDescs.length; i++) { + mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); + } + onAuthDescriptionsUpdated(); + } + + private void onAuthDescriptionsUpdated() { + // Create list of providers to show on preference screen + for (int i = 0; i < mAuthDescs.length; i++) { + final String accountType = mAuthDescs[i].type; + final CharSequence providerName = getLabelForType(accountType); + + // Skip preferences for authorities not specified. If no authorities specified, + // then include them all. + final List accountAuths = getAuthoritiesForAccountType(accountType); + boolean addAccountPref = true; + if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) { + addAccountPref = false; + for (int k = 0; k < mAuthorities.length; k++) { + if (accountAuths.contains(mAuthorities[k])) { + addAccountPref = true; + break; + } + } + } + if (addAccountPref && mAccountTypesFilter != null + && !mAccountTypesFilter.contains(accountType)) { + addAccountPref = false; + } + if (addAccountPref) { + mProviderList.add( + new ProviderEntry(providerName, accountType)); + } else { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need"); + } + } + } + final Context context = mScreen.getContext(); + if (mProviderList.size() == 1) { + // There's only one provider that matches. If it is disabled by admin show the + // support dialog otherwise run it. + final RestrictedLockUtils.EnforcedAdmin admin = + RestrictedLockUtils.checkIfAccountManagementDisabled( + context, mProviderList.get(0).getType(), mUserHandle.getIdentifier()); + if (admin != null) { + mActivity.setResult(RESULT_CANCELED, + RestrictedLockUtils.getShowAdminSupportDetailsIntent( + context, admin)); + mActivity.finish(); + } else { + finishWithAccountType(mProviderList.get(0).getType()); + } + } else if (mProviderList.size() > 0) { + Collections.sort(mProviderList); + for (ProviderEntry pref : mProviderList) { + final Drawable drawable = getDrawableForType(pref.getType()); + final ProviderPreference p = new ProviderPreference(context, + pref.getType(), drawable, pref.getName()); + p.setKey(pref.getType().toString()); + p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier()); + mScreen.addPreference(p); + } + } else { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + final StringBuilder auths = new StringBuilder(); + for (String a : mAuthorities) { + auths.append(a); + auths.append(' '); + } + Log.v(TAG, "No providers found for authorities: " + auths); + } + mActivity.setResult(RESULT_CANCELED); + mActivity.finish(); + } + } + + private List getAuthoritiesForAccountType(String type) { + if (mAccountTypeToAuthorities == null) { + mAccountTypeToAuthorities = Maps.newHashMap(); + final SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser( + mUserHandle.getIdentifier()); + for (int i = 0, n = syncAdapters.length; i < n; i++) { + final SyncAdapterType sa = syncAdapters[i]; + List authorities = mAccountTypeToAuthorities.get(sa.accountType); + if (authorities == null) { + authorities = new ArrayList<>(); + mAccountTypeToAuthorities.put(sa.accountType, authorities); + } + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "added authority " + sa.authority + " to accountType " + + sa.accountType); + } + authorities.add(sa.authority); + } + } + return mAccountTypeToAuthorities.get(type); + } + + /** + * Gets an icon associated with a particular account type. If none found, return null. + * + * @param accountType the type of account + * @return a drawable for the icon or a default icon returned by + * {@link PackageManager#getDefaultActivityIcon} if one cannot be found. + */ + @VisibleForTesting + Drawable getDrawableForType(final String accountType) { + Drawable icon = null; + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + final AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + final Context authContext = mActivity + .createPackageContextAsUser(desc.packageName, 0, mUserHandle); + icon = mContext.getPackageManager().getUserBadgedIcon( + authContext.getDrawable(desc.iconId), mUserHandle); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "No icon name for account type " + accountType); + } catch (Resources.NotFoundException e) { + Log.w(TAG, "No icon resource for account type " + accountType); + } + } + if (icon != null) { + return icon; + } else { + return mContext.getPackageManager().getDefaultActivityIcon(); + } + } + + /** + * Gets the label associated with a particular account type. If none found, return null. + * + * @param accountType the type of account + * @return a CharSequence for the label or null if one cannot be found. + */ + @VisibleForTesting + CharSequence getLabelForType(final String accountType) { + CharSequence label = null; + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + final AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + final Context authContext = mActivity + .createPackageContextAsUser(desc.packageName, 0, mUserHandle); + label = authContext.getResources().getText(desc.labelId); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "No label name for account type " + accountType); + } catch (Resources.NotFoundException e) { + Log.w(TAG, "No label resource for account type " + accountType); + } + } + return label; + } + + private void finishWithAccountType(String accountType) { + Intent intent = new Intent(); + intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType); + intent.putExtra(EXTRA_USER, mUserHandle); + mActivity.setResult(RESULT_OK, intent); + mActivity.finish(); + } +} diff --git a/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceController.java b/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceController.java new file mode 100644 index 0000000000..e8a444fdfb --- /dev/null +++ b/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceController.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.FooterPreferenceMixin; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceScreen; + +public class EnterpriseDisclosurePreferenceController extends BasePreferenceController { + + private final EnterprisePrivacyFeatureProvider mFeatureProvider; + private FooterPreferenceMixin mFooterPreferenceMixin; + private PreferenceScreen mScreen; + + public EnterpriseDisclosurePreferenceController(Context context) { + // Preference key doesn't matter as we are creating the preference in code. + super(context, "add_account_enterprise_disclosure_footer"); + + mFeatureProvider = FeatureFactory.getFactory(mContext) + .getEnterprisePrivacyFeatureProvider(mContext); + } + + public void setFooterPreferenceMixin(FooterPreferenceMixin footerPreferenceMixin) { + mFooterPreferenceMixin = footerPreferenceMixin; + } + + @Override + public int getAvailabilityStatus() { + if (getDisclosure() == null) { + return DISABLED_UNSUPPORTED; + } + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mScreen = screen; + addEnterpriseDisclosure(); + } + + @VisibleForTesting + CharSequence getDisclosure() { + return mFeatureProvider.getDeviceOwnerDisclosure(); + } + + private void addEnterpriseDisclosure() { + final CharSequence disclosure = getDisclosure(); + if (disclosure == null) { + return; + } + final FooterPreference enterpriseDisclosurePreference = + mFooterPreferenceMixin.createFooterPreference(); + enterpriseDisclosurePreference.setSelectable(false); + enterpriseDisclosurePreference.setTitle(disclosure); + mScreen.addPreference(enterpriseDisclosurePreference); + } +} diff --git a/src/com/android/settings/accounts/ProviderEntry.java b/src/com/android/settings/accounts/ProviderEntry.java new file mode 100644 index 0000000000..cf55e1423f --- /dev/null +++ b/src/com/android/settings/accounts/ProviderEntry.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import com.android.internal.util.CharSequences; + +public class ProviderEntry implements Comparable { + private final CharSequence name; + private final String type; + + ProviderEntry(CharSequence providerName, String accountType) { + name = providerName; + type = accountType; + } + + public int compareTo(ProviderEntry another) { + if (name == null) { + return -1; + } + if (another.name == null) { + return +1; + } + return CharSequences.compareToIgnoreCase(name, another.name); + } + + public CharSequence getName() { + return name; + } + + public String getType() { + return type; + } +} \ No newline at end of file diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index be9b722a5a..ced158eb3e 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -31,7 +31,7 @@ import com.android.settings.accessibility.CaptionPropertiesFragment; import com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment; import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.accounts.AccountSyncSettings; -import com.android.settings.accounts.ChooseAccountActivity; +import com.android.settings.accounts.ChooseAccountFragment; import com.android.settings.accounts.ManagedProfileSettings; import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.applications.DefaultAppSettings; @@ -236,7 +236,7 @@ public class SettingsGateway { PictureInPictureSettings.class.getName(), PictureInPictureDetails.class.getName(), ManagedProfileSettings.class.getName(), - ChooseAccountActivity.class.getName(), + ChooseAccountFragment.class.getName(), IccLockSettings.class.getName(), TestingSettings.class.getName(), WifiAPITest.class.getName(), diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 8523b2f1ab..57b75e1eb8 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -17,7 +17,6 @@ com.android.settings.applications.ManageDomainUrls com.android.settings.applications.appinfo.WriteSettingsDetails com.android.settings.applications.ProcessStatsSummary com.android.settings.users.RestrictedProfileSettings -com.android.settings.accounts.ChooseAccountActivity com.android.settings.accessibility.ToggleAutoclickPreferenceFragment com.android.settings.applications.AppLaunchSettings com.android.settings.applications.ProcessStatsUi diff --git a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java new file mode 100644 index 0000000000..67e01f8817 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +import android.accounts.AuthenticatorDescription; +import android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.SyncAdapterType; +import android.graphics.drawable.ColorDrawable; +import android.os.UserHandle; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowAccountManager; +import com.android.settings.testutils.shadow.ShadowContentResolver; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import androidx.preference.Preference; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class, + ShadowRestrictedLockUtils.class}) +public class ChooseAccountPreferenceControllerTest { + + private Context mContext; + private ChooseAccountPreferenceController mController; + private Activity mActivity; + private PreferenceManager mPreferenceManager; + private PreferenceScreen mPreferenceScreen; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = spy(new ChooseAccountPreferenceController(mContext, "controller_key")); + mActivity = Robolectric.setupActivity(Activity.class); + mPreferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + } + + @After + public void tearDown() { + ShadowContentResolver.reset(); + ShadowAccountManager.resetAuthenticator(); + ShadowRestrictedLockUtils.clearDisabledTypes(); + } + + @Test + public void getAvailabilityStatus_byDefault_shouldBeShown() { + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); + } + + @Test + public void handlePreferenceTreeClick_notProviderPreference_shouldReturnFalse() { + final Preference preference = new Preference(mContext); + assertThat(mController.handlePreferenceTreeClick(preference)).isFalse(); + } + + @Test + public void handlePreferenceTreeClick_isProviderPreference_shouldFinishFragment() { + final ProviderPreference providerPreference = new ProviderPreference(mContext, + "account_type", null /* icon */, "provider_name"); + + mController.initialize(null, null, null, mActivity); + mController.handlePreferenceTreeClick(providerPreference); + + assertThat(mActivity.isFinishing()).isTrue(); + } + + @Test + public void updateAuthDescriptions_oneProvider_shouldNotAddPreference() { + final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", + "com.android.settings", + R.string.header_add_an_account, 0, 0, 0, false); + ShadowAccountManager.addAuthenticator(authDesc); + + final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, + "com.acct1" /* accountType */, false /* userVisible */, + true /* supportsUploading */)}; + ShadowContentResolver.setSyncAdapterTypes(syncAdapters); + + ShadowRestrictedLockUtils.setHasSystemFeature(true); + ShadowRestrictedLockUtils.setDevicePolicyManager(mock(DevicePolicyManager.class)); + ShadowRestrictedLockUtils.setDisabledTypes(new String[] {"test_type"}); + + doReturn("label").when(mController).getLabelForType(anyString()); + + mController.initialize(null, null, new UserHandle(3), mActivity); + mController.displayPreference(mPreferenceScreen); + + assertThat(mActivity.isFinishing()).isTrue(); + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void updateAuthDescriptions_oneAdminDisabledProvider_shouldNotAddPreference() { + final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", + "com.android.settings", + R.string.header_add_an_account, 0, 0, 0, false); + ShadowAccountManager.addAuthenticator(authDesc); + + final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, + "com.acct1" /* accountType */, false /* userVisible */, + true /* supportsUploading */)}; + ShadowContentResolver.setSyncAdapterTypes(syncAdapters); + + ShadowRestrictedLockUtils.setHasSystemFeature(true); + ShadowRestrictedLockUtils.setDevicePolicyManager(mock(DevicePolicyManager.class)); + ShadowRestrictedLockUtils.setDisabledTypes(new String[] {"com.acct1"}); + + doReturn("label").when(mController).getLabelForType(anyString()); + + mController.initialize(null, null, new UserHandle(3), mActivity); + mController.displayPreference(mPreferenceScreen); + + assertThat(mActivity.isFinishing()).isTrue(); + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void updateAuthDescriptions_noProvider_shouldNotAddPreference() { + final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", + "com.android.settings", + R.string.header_add_an_account, 0, 0, 0, false); + ShadowAccountManager.addAuthenticator(authDesc); + + final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, + "com.acct1" /* accountType */, false /* userVisible */, + true /* supportsUploading */)}; + ShadowContentResolver.setSyncAdapterTypes(syncAdapters); + + doReturn("label").when(mController).getLabelForType(anyString()); + + mController.initialize(new String[] {"test_authoritiy1"}, null, new UserHandle(3), + mActivity); + mController.displayPreference(mPreferenceScreen); + + assertThat(mActivity.isFinishing()).isTrue(); + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void + updateAuthDescriptions_twoProvider_shouldAddTwoPreference() { + final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", + "com.android.settings", + R.string.header_add_an_account, 0, 0, 0, false); + final AuthenticatorDescription authDesc2 = new AuthenticatorDescription("com.acct2", + "com.android.settings", + R.string.header_add_an_account, 0, 0, 0, false); + ShadowAccountManager.addAuthenticator(authDesc); + ShadowAccountManager.addAuthenticator(authDesc2); + + final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, + "com.acct1" /* accountType */, false /* userVisible */, + true /* supportsUploading */), new SyncAdapterType("authority2" /* authority */, + "com.acct2" /* accountType */, false /* userVisible */, + true /* supportsUploading */)}; + ShadowContentResolver.setSyncAdapterTypes(syncAdapters); + + doReturn("label").when(mController).getLabelForType(anyString()); + doReturn("label2").when(mController).getLabelForType(anyString()); + doReturn(new ColorDrawable()).when(mController).getDrawableForType(anyString()); + doReturn(new ColorDrawable()).when(mController).getDrawableForType(anyString()); + + mController.initialize(null, null, new UserHandle(3), mActivity); + mController.displayPreference(mPreferenceScreen); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(2); + } +} diff --git a/tests/robotests/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceControllerTest.java new file mode 100644 index 0000000000..4ad0982d6a --- /dev/null +++ b/tests/robotests/src/com/android/settings/accounts/EnterpriseDisclosurePreferenceControllerTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 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.settings.accounts; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.widget.FooterPreferenceMixin; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +public class EnterpriseDisclosurePreferenceControllerTest { + + private static final String TEST_DISCLOSURE = "This is a test disclosure."; + + private ChooseAccountFragment mFragment; + private Context mContext; + private EnterpriseDisclosurePreferenceController mController; + private FooterPreferenceMixin mFooterPreferenceMixin; + private PreferenceManager mPreferenceManager; + private PreferenceScreen mPreferenceScreen; + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = spy(new EnterpriseDisclosurePreferenceController(mContext)); + mFragment = spy(new ChooseAccountFragment()); + mFooterPreferenceMixin = new FooterPreferenceMixin(mFragment, mFragment.getLifecycle()); + mPreferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + } + + @Test + public void getAvailabilityStatus_hasDisclosure_shouldBeAvailable() { + doReturn(TEST_DISCLOSURE).when(mController).getDisclosure(); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noDisclosure_shouldBeDisabled() { + doReturn(null).when(mController).getDisclosure(); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.DISABLED_UNSUPPORTED); + } + + @Test + public void displayPreference_hasDisclosure_shouldSetTitle() { + doReturn(TEST_DISCLOSURE).when(mController).getDisclosure(); + doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); + doReturn(mPreferenceManager).when(mFragment).getPreferenceManager(); + + mController.setFooterPreferenceMixin(mFooterPreferenceMixin); + mController.displayPreference(mPreferenceScreen); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(1); + assertThat(mPreferenceScreen.getPreference(0).getTitle()).isEqualTo(TEST_DISCLOSURE); + } + + @Test + public void displayPreference_noDisclosure_shouldBeInvisible() { + doReturn(null).when(mController).getDisclosure(); + + mController.displayPreference(mPreferenceScreen); + + assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java index 2bccccc74d..03aabb5dbb 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java @@ -22,10 +22,24 @@ import android.accounts.AuthenticatorDescription; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import java.util.HashMap; +import java.util.Map; + @Implements(AccountManager.class) -public class ShadowAccountManager { +public class ShadowAccountManager{ + + private static final Map sAuthenticators = new HashMap<>(); + @Implementation public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) { - return null; + return sAuthenticators.values().toArray(new AuthenticatorDescription[sAuthenticators.size()]); + } + + public static void addAuthenticator(AuthenticatorDescription authenticator) { + sAuthenticators.put(authenticator.type, authenticator); + } + + public static void resetAuthenticator() { + sAuthenticators.clear(); } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java index c53f7712bf..30e6401f53 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java @@ -16,6 +16,7 @@ package com.android.settings.testutils.shadow; import android.annotation.UserIdInt; +import android.app.admin.DevicePolicyManager; import android.content.Context; import com.android.internal.util.ArrayUtils; @@ -28,26 +29,31 @@ import org.robolectric.annotation.Resetter; @Implements(RestrictedLockUtils.class) public class ShadowRestrictedLockUtils { - private static boolean isRestricted; - private static String[] restrictedPkgs; - private static boolean adminSupportDetailsIntentLaunched; - private static int keyguardDisabledFeatures; + + private static boolean sIsRestricted; + private static boolean sAdminSupportDetailsIntentLaunched; + private static boolean sHasSystemFeature; + private static String[] sRestrictedPkgs; + private static DevicePolicyManager sDevicePolicyManager; + private static String[] sDisabledTypes; + private static int sKeyguardDisabledFeatures; @Resetter public static void reset() { - isRestricted = false; - restrictedPkgs = null; - adminSupportDetailsIntentLaunched = false; - keyguardDisabledFeatures = 0; + sIsRestricted = false; + sRestrictedPkgs = null; + sAdminSupportDetailsIntentLaunched = false; + sKeyguardDisabledFeatures = 0; + sDisabledTypes = new String[0]; } @Implementation public static EnforcedAdmin checkIfMeteredDataRestricted(Context context, String packageName, int userId) { - if (isRestricted) { + if (sIsRestricted) { return new EnforcedAdmin(); } - if (ArrayUtils.contains(restrictedPkgs, packageName)) { + if (ArrayUtils.contains(sRestrictedPkgs, packageName)) { return new EnforcedAdmin(); } return null; @@ -55,32 +61,67 @@ public class ShadowRestrictedLockUtils { @Implementation public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) { - adminSupportDetailsIntentLaunched = true; + sAdminSupportDetailsIntentLaunched = true; + } + + @Implementation + public static EnforcedAdmin checkIfAccountManagementDisabled(Context context, + String accountType, int userId) { + if (accountType == null) { + return null; + } + if (!sHasSystemFeature || sDevicePolicyManager == null) { + return null; + } + boolean isAccountTypeDisabled = false; + if (ArrayUtils.contains(sDisabledTypes, accountType)) { + isAccountTypeDisabled = true; + } + if (!isAccountTypeDisabled) { + return null; + } + return new EnforcedAdmin(); } @Implementation public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context, int features, final @UserIdInt int userId) { - return (keyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin(); + return (sKeyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin(); } public static boolean hasAdminSupportDetailsIntentLaunched() { - return adminSupportDetailsIntentLaunched; + return sAdminSupportDetailsIntentLaunched; } public static void clearAdminSupportDetailsIntentLaunch() { - adminSupportDetailsIntentLaunched = false; + sAdminSupportDetailsIntentLaunched = false; } public static void setRestricted(boolean restricted) { - isRestricted = restricted; + sIsRestricted = restricted; } public static void setRestrictedPkgs(String... pkgs) { - restrictedPkgs = pkgs; + sRestrictedPkgs = pkgs; + } + + public static void setHasSystemFeature(boolean hasSystemFeature) { + sHasSystemFeature = hasSystemFeature; + } + + public static void setDevicePolicyManager(DevicePolicyManager dpm) { + sDevicePolicyManager = dpm; + } + + public static void setDisabledTypes(String[] disabledTypes) { + sDisabledTypes = disabledTypes; + } + + public static void clearDisabledTypes() { + sDisabledTypes = new String[0]; } public static void setKeyguardDisabledFeatures(int features) { - keyguardDisabledFeatures = features; + sKeyguardDisabledFeatures = features; } } -- cgit v1.2.3