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
This commit is contained in:
Emily Chuang
2018-04-12 10:12:28 +08:00
committed by Fan Zhang
parent 8efbe6e255
commit b279b1c025
12 changed files with 712 additions and 153 deletions

View File

@@ -2341,7 +2341,7 @@
android:label="@string/header_add_an_account" android:label="@string/header_add_an_account"
android:configChanges="orientation|keyboardHidden|screenSize"> android:configChanges="orientation|keyboardHidden|screenSize">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS" <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.accounts.ChooseAccountActivity" /> android:value="com.android.settings.accounts.ChooseAccountFragment" />
</activity> </activity>
<activity android:name=".CryptKeeper" <activity android:name=".CryptKeeper"

View File

@@ -14,6 +14,9 @@
limitations under the License. limitations under the License.
--> -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
</PreferenceScreen> xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="add_account_screen"
android:title="@string/header_add_an_account"
settings:controller="com.android.settings.accounts.ChooseAccountPreferenceController" />

View File

@@ -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<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildControllers(context);
}
private static List<AbstractPreferenceController> buildControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new EnterpriseDisclosurePreferenceController(context));
return controllers;
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
final ArrayList<SearchIndexableResource> result = new ArrayList<>();
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.add_account_settings;
result.add(sir);
return result;
}
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
return buildControllers(context);
}
};
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 The Android Open Source Project * Copyright (C) 2018 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -30,24 +30,11 @@ import android.content.SyncAdapterType;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import android.util.Log; import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.core.BasePreferenceController;
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;
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 com.google.android.collect.Maps;
@@ -55,89 +42,87 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
/** /**
* 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 * 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. * which the action needs to be performed is different to the one the Settings App will run in.
*/ */
public class ChooseAccountActivity extends SettingsPreferenceFragment { public class ChooseAccountPreferenceController extends BasePreferenceController {
private static final String TAG = "ChooseAccountActivity"; private static final String TAG = "ChooseAccountPrefCtrler";
private EnterprisePrivacyFeatureProvider mFeatureProvider; private final List<ProviderEntry> mProviderList;
private FooterPreference mEnterpriseDisclosurePreference = null; private final Map<String, AuthenticatorDescription> mTypeToAuthDescription;
private String[] mAuthorities; private String[] mAuthorities;
private PreferenceGroup mAddAccountGroup; private Set<String> mAccountTypesFilter;
private final ArrayList<ProviderEntry> mProviderList = new ArrayList<ProviderEntry>();
public HashSet<String> mAccountTypesFilter;
private AuthenticatorDescription[] mAuthDescs; private AuthenticatorDescription[] mAuthDescs;
private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null; private Map<String, List<String>> mAccountTypeToAuthorities;
private Map<String, AuthenticatorDescription> mTypeToAuthDescription
= new HashMap<String, AuthenticatorDescription>();
// The UserHandle of the user we are choosing an account for // The UserHandle of the user we are choosing an account for
private UserHandle mUserHandle; private UserHandle mUserHandle;
private UserManager mUm; private Activity mActivity;
private PreferenceScreen mScreen;
private static class ProviderEntry implements Comparable<ProviderEntry> { public ChooseAccountPreferenceController(Context context, String preferenceKey) {
private final CharSequence name; super(context, preferenceKey);
private final String type;
ProviderEntry(CharSequence providerName, String accountType) {
name = providerName;
type = accountType;
}
public int compareTo(ProviderEntry another) { mProviderList = new ArrayList<>();
if (name == null) { mTypeToAuthDescription = new HashMap<>();
return -1;
}
if (another.name == null) {
return +1;
}
return CharSequences.compareToIgnoreCase(name, another.name);
}
} }
@Override public void initialize(String[] authorities, String[] accountTypesFilter, UserHandle userHandle,
public int getMetricsCategory() { Activity activity) {
return MetricsEvent.ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY; mActivity = activity;
} mAuthorities = authorities;
mUserHandle = userHandle;
@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) { if (accountTypesFilter != null) {
mAccountTypesFilter = new HashSet<String>(); mAccountTypesFilter = new HashSet<>();
for (String accountType : accountTypesFilter) { for (String accountType : accountTypesFilter) {
mAccountTypesFilter.add(accountType); mAccountTypesFilter.add(accountType);
} }
} }
mAddAccountGroup = getPreferenceScreen(); }
mUm = UserManager.get(getContext());
mUserHandle = Utils.getSecureTargetUser(getActivity().getActivityToken(), mUm, @Override
null /* arguments */, getIntent().getExtras()); public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mScreen = screen;
updateAuthDescriptions(); 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() * Updates provider icons. Subclasses should call this in onCreate()
* and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated().
*/ */
private void updateAuthDescriptions() { private void updateAuthDescriptions() {
mAuthDescs = AccountManager.get(getContext()).getAuthenticatorTypesAsUser( mAuthDescs = AccountManager.get(mContext).getAuthenticatorTypesAsUser(
mUserHandle.getIdentifier()); mUserHandle.getIdentifier());
for (int i = 0; i < mAuthDescs.length; i++) { for (int i = 0; i < mAuthDescs.length; i++) {
mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
@@ -148,12 +133,12 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
private void onAuthDescriptionsUpdated() { private void onAuthDescriptionsUpdated() {
// Create list of providers to show on preference screen // Create list of providers to show on preference screen
for (int i = 0; i < mAuthDescs.length; i++) { for (int i = 0; i < mAuthDescs.length; i++) {
String accountType = mAuthDescs[i].type; final String accountType = mAuthDescs[i].type;
CharSequence providerName = getLabelForType(accountType); final CharSequence providerName = getLabelForType(accountType);
// Skip preferences for authorities not specified. If no authorities specified, // Skip preferences for authorities not specified. If no authorities specified,
// then include them all. // then include them all.
ArrayList<String> accountAuths = getAuthoritiesForAccountType(accountType); final List<String> accountAuths = getAuthoritiesForAccountType(accountType);
boolean addAccountPref = true; boolean addAccountPref = true;
if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) { if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) {
addAccountPref = false; addAccountPref = false;
@@ -169,38 +154,39 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
addAccountPref = false; addAccountPref = false;
} }
if (addAccountPref) { if (addAccountPref) {
mProviderList.add(new ProviderEntry(providerName, accountType)); mProviderList.add(
new ProviderEntry(providerName, accountType));
} else { } else {
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need"); Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need");
} }
} }
} }
final Context context = mScreen.getContext();
final Context context = getPreferenceScreen().getContext();
if (mProviderList.size() == 1) { if (mProviderList.size() == 1) {
// There's only one provider that matches. If it is disabled by admin show the // There's only one provider that matches. If it is disabled by admin show the
// support dialog otherwise run it. // support dialog otherwise run it.
EnforcedAdmin admin = RestrictedLockUtils.checkIfAccountManagementDisabled( final RestrictedLockUtils.EnforcedAdmin admin =
context, mProviderList.get(0).type, mUserHandle.getIdentifier()); RestrictedLockUtils.checkIfAccountManagementDisabled(
context, mProviderList.get(0).getType(), mUserHandle.getIdentifier());
if (admin != null) { if (admin != null) {
setResult(RESULT_CANCELED, RestrictedLockUtils.getShowAdminSupportDetailsIntent( mActivity.setResult(RESULT_CANCELED,
context, admin)); RestrictedLockUtils.getShowAdminSupportDetailsIntent(
finish(); context, admin));
mActivity.finish();
} else { } else {
finishWithAccountType(mProviderList.get(0).type); finishWithAccountType(mProviderList.get(0).getType());
} }
} else if (mProviderList.size() > 0) { } else if (mProviderList.size() > 0) {
Collections.sort(mProviderList); Collections.sort(mProviderList);
mAddAccountGroup.removeAll();
for (ProviderEntry pref : mProviderList) { for (ProviderEntry pref : mProviderList) {
Drawable drawable = getDrawableForType(pref.type); final Drawable drawable = getDrawableForType(pref.getType());
ProviderPreference p = new ProviderPreference(getPreferenceScreen().getContext(), final ProviderPreference p = new ProviderPreference(context,
pref.type, drawable, pref.name); pref.getType(), drawable, pref.getName());
p.setKey(pref.getType().toString());
p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier()); p.checkAccountManagementAndSetDisabled(mUserHandle.getIdentifier());
mAddAccountGroup.addPreference(p); mScreen.addPreference(p);
} }
addEnterpriseDisclosure();
} else { } else {
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
final StringBuilder auths = new StringBuilder(); final StringBuilder auths = new StringBuilder();
@@ -210,38 +196,25 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
} }
Log.v(TAG, "No providers found for authorities: " + auths); Log.v(TAG, "No providers found for authorities: " + auths);
} }
setResult(RESULT_CANCELED); mActivity.setResult(RESULT_CANCELED);
finish(); mActivity.finish();
} }
} }
private void addEnterpriseDisclosure() { private List<String> getAuthoritiesForAccountType(String type) {
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<String> getAuthoritiesForAccountType(String type) {
if (mAccountTypeToAuthorities == null) { if (mAccountTypeToAuthorities == null) {
mAccountTypeToAuthorities = Maps.newHashMap(); mAccountTypeToAuthorities = Maps.newHashMap();
SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser( final SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
mUserHandle.getIdentifier()); mUserHandle.getIdentifier());
for (int i = 0, n = syncAdapters.length; i < n; i++) { for (int i = 0, n = syncAdapters.length; i < n; i++) {
final SyncAdapterType sa = syncAdapters[i]; final SyncAdapterType sa = syncAdapters[i];
ArrayList<String> authorities = mAccountTypeToAuthorities.get(sa.accountType); List<String> authorities = mAccountTypeToAuthorities.get(sa.accountType);
if (authorities == null) { if (authorities == null) {
authorities = new ArrayList<String>(); authorities = new ArrayList<>();
mAccountTypeToAuthorities.put(sa.accountType, authorities); mAccountTypeToAuthorities.put(sa.accountType, authorities);
} }
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "added authority " + sa.authority + " to accountType " Log.v(TAG, "added authority " + sa.authority + " to accountType "
+ sa.accountType); + sa.accountType);
} }
authorities.add(sa.authority); authorities.add(sa.authority);
@@ -252,18 +225,20 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
/** /**
* Gets an icon associated with a particular account type. If none found, return null. * Gets an icon associated with a particular account type. If none found, return null.
*
* @param accountType the type of account * @param accountType the type of account
* @return a drawable for the icon or a default icon returned by * @return a drawable for the icon or a default icon returned by
* {@link PackageManager#getDefaultActivityIcon} if one cannot be found. * {@link PackageManager#getDefaultActivityIcon} if one cannot be found.
*/ */
protected Drawable getDrawableForType(final String accountType) { @VisibleForTesting
Drawable getDrawableForType(final String accountType) {
Drawable icon = null; Drawable icon = null;
if (mTypeToAuthDescription.containsKey(accountType)) { if (mTypeToAuthDescription.containsKey(accountType)) {
try { try {
AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); final AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
Context authContext = getActivity() final Context authContext = mActivity
.createPackageContextAsUser(desc.packageName, 0, mUserHandle); .createPackageContextAsUser(desc.packageName, 0, mUserHandle);
icon = getPackageManager().getUserBadgedIcon( icon = mContext.getPackageManager().getUserBadgedIcon(
authContext.getDrawable(desc.iconId), mUserHandle); authContext.getDrawable(desc.iconId), mUserHandle);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "No icon name for account type " + accountType); Log.w(TAG, "No icon name for account type " + accountType);
@@ -274,21 +249,23 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
if (icon != null) { if (icon != null) {
return icon; return icon;
} else { } else {
return getPackageManager().getDefaultActivityIcon(); return mContext.getPackageManager().getDefaultActivityIcon();
} }
} }
/** /**
* Gets the label associated with a particular account type. If none found, return null. * Gets the label associated with a particular account type. If none found, return null.
*
* @param accountType the type of account * @param accountType the type of account
* @return a CharSequence for the label or null if one cannot be found. * @return a CharSequence for the label or null if one cannot be found.
*/ */
protected CharSequence getLabelForType(final String accountType) { @VisibleForTesting
CharSequence getLabelForType(final String accountType) {
CharSequence label = null; CharSequence label = null;
if (mTypeToAuthDescription.containsKey(accountType)) { if (mTypeToAuthDescription.containsKey(accountType)) {
try { try {
AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); final AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
Context authContext = getActivity() final Context authContext = mActivity
.createPackageContextAsUser(desc.packageName, 0, mUserHandle); .createPackageContextAsUser(desc.packageName, 0, mUserHandle);
label = authContext.getResources().getText(desc.labelId); label = authContext.getResources().getText(desc.labelId);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
@@ -300,23 +277,11 @@ public class ChooseAccountActivity extends SettingsPreferenceFragment {
return label; 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) { private void finishWithAccountType(String accountType) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType); intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType);
intent.putExtra(EXTRA_USER, mUserHandle); intent.putExtra(EXTRA_USER, mUserHandle);
setResult(RESULT_OK, intent); mActivity.setResult(RESULT_OK, intent);
finish(); mActivity.finish();
} }
} }

View File

@@ -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);
}
}

View File

@@ -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<ProviderEntry> {
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;
}
}

View File

@@ -31,7 +31,7 @@ import com.android.settings.accessibility.CaptionPropertiesFragment;
import com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment; import com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment;
import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.accounts.AccountDashboardFragment;
import com.android.settings.accounts.AccountSyncSettings; 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.accounts.ManagedProfileSettings;
import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.applications.AppAndNotificationDashboardFragment;
import com.android.settings.applications.DefaultAppSettings; import com.android.settings.applications.DefaultAppSettings;
@@ -236,7 +236,7 @@ public class SettingsGateway {
PictureInPictureSettings.class.getName(), PictureInPictureSettings.class.getName(),
PictureInPictureDetails.class.getName(), PictureInPictureDetails.class.getName(),
ManagedProfileSettings.class.getName(), ManagedProfileSettings.class.getName(),
ChooseAccountActivity.class.getName(), ChooseAccountFragment.class.getName(),
IccLockSettings.class.getName(), IccLockSettings.class.getName(),
TestingSettings.class.getName(), TestingSettings.class.getName(),
WifiAPITest.class.getName(), WifiAPITest.class.getName(),

View File

@@ -17,7 +17,6 @@ com.android.settings.applications.ManageDomainUrls
com.android.settings.applications.appinfo.WriteSettingsDetails com.android.settings.applications.appinfo.WriteSettingsDetails
com.android.settings.applications.ProcessStatsSummary com.android.settings.applications.ProcessStatsSummary
com.android.settings.users.RestrictedProfileSettings com.android.settings.users.RestrictedProfileSettings
com.android.settings.accounts.ChooseAccountActivity
com.android.settings.accessibility.ToggleAutoclickPreferenceFragment com.android.settings.accessibility.ToggleAutoclickPreferenceFragment
com.android.settings.applications.AppLaunchSettings com.android.settings.applications.AppLaunchSettings
com.android.settings.applications.ProcessStatsUi com.android.settings.applications.ProcessStatsUi

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -22,10 +22,24 @@ import android.accounts.AuthenticatorDescription;
import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements;
import java.util.HashMap;
import java.util.Map;
@Implements(AccountManager.class) @Implements(AccountManager.class)
public class ShadowAccountManager { public class ShadowAccountManager{
private static final Map<String, AuthenticatorDescription> sAuthenticators = new HashMap<>();
@Implementation @Implementation
public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) { 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();
} }
} }

View File

@@ -16,6 +16,7 @@
package com.android.settings.testutils.shadow; package com.android.settings.testutils.shadow;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
@@ -28,26 +29,31 @@ import org.robolectric.annotation.Resetter;
@Implements(RestrictedLockUtils.class) @Implements(RestrictedLockUtils.class)
public class ShadowRestrictedLockUtils { public class ShadowRestrictedLockUtils {
private static boolean isRestricted;
private static String[] restrictedPkgs; private static boolean sIsRestricted;
private static boolean adminSupportDetailsIntentLaunched; private static boolean sAdminSupportDetailsIntentLaunched;
private static int keyguardDisabledFeatures; private static boolean sHasSystemFeature;
private static String[] sRestrictedPkgs;
private static DevicePolicyManager sDevicePolicyManager;
private static String[] sDisabledTypes;
private static int sKeyguardDisabledFeatures;
@Resetter @Resetter
public static void reset() { public static void reset() {
isRestricted = false; sIsRestricted = false;
restrictedPkgs = null; sRestrictedPkgs = null;
adminSupportDetailsIntentLaunched = false; sAdminSupportDetailsIntentLaunched = false;
keyguardDisabledFeatures = 0; sKeyguardDisabledFeatures = 0;
sDisabledTypes = new String[0];
} }
@Implementation @Implementation
public static EnforcedAdmin checkIfMeteredDataRestricted(Context context, public static EnforcedAdmin checkIfMeteredDataRestricted(Context context,
String packageName, int userId) { String packageName, int userId) {
if (isRestricted) { if (sIsRestricted) {
return new EnforcedAdmin(); return new EnforcedAdmin();
} }
if (ArrayUtils.contains(restrictedPkgs, packageName)) { if (ArrayUtils.contains(sRestrictedPkgs, packageName)) {
return new EnforcedAdmin(); return new EnforcedAdmin();
} }
return null; return null;
@@ -55,32 +61,67 @@ public class ShadowRestrictedLockUtils {
@Implementation @Implementation
public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) { 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 @Implementation
public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context, public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
int features, final @UserIdInt int userId) { int features, final @UserIdInt int userId) {
return (keyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin(); return (sKeyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin();
} }
public static boolean hasAdminSupportDetailsIntentLaunched() { public static boolean hasAdminSupportDetailsIntentLaunched() {
return adminSupportDetailsIntentLaunched; return sAdminSupportDetailsIntentLaunched;
} }
public static void clearAdminSupportDetailsIntentLaunch() { public static void clearAdminSupportDetailsIntentLaunch() {
adminSupportDetailsIntentLaunched = false; sAdminSupportDetailsIntentLaunched = false;
} }
public static void setRestricted(boolean restricted) { public static void setRestricted(boolean restricted) {
isRestricted = restricted; sIsRestricted = restricted;
} }
public static void setRestrictedPkgs(String... pkgs) { 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) { public static void setKeyguardDisabledFeatures(int features) {
keyguardDisabledFeatures = features; sKeyguardDisabledFeatures = features;
} }
} }