Add account preference controller.
- Add account preference controller and move the handling for displaying user's accounts from AccountSettings to the controller. - Move AccountPreference and RemoveUserFragment from inner class to standalone class. - Add AccountRestrictionHelper to handle API that needs to be mocked for testing. Bug: 31801423 Test: make RunSettingsRoboTests Change-Id: I3d16d0b6a8922a8abec7037c52b7a4de2d76eb0d
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
<!-- Copyright (C) 2016 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.
|
||||||
@@ -16,40 +16,40 @@
|
|||||||
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
|
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
|
||||||
android:key="account"
|
|
||||||
android:title="@string/account_settings_title"
|
android:title="@string/account_settings_title"
|
||||||
settings:keywords="@string/keywords_accounts">
|
settings:keywords="@string/keywords_accounts">
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:key="account_for_header"
|
|
||||||
android:title="@string/account_for_section_header" />
|
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="emergency_info"
|
android:key="emergency_info"
|
||||||
android:title="@string/emergency_info_title" />
|
android:title="@string/emergency_info_title"
|
||||||
|
android:order="100"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="account_configuration_header"
|
android:key="account_configuration_header"
|
||||||
android:title="@string/configure_section_header">
|
android:title="@string/configure_section_header"
|
||||||
|
android:order="101">
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="auto_sync_account_data"
|
android:key="auto_sync_account_data"
|
||||||
android:title="@string/auto_sync_account_title" />
|
android:title="@string/auto_sync_account_title"
|
||||||
|
android:order="102" />
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="auto_sync_work_account_data"
|
android:key="auto_sync_work_account_data"
|
||||||
android:title="@string/account_settings_menu_auto_sync_work" />
|
android:title="@string/account_settings_menu_auto_sync_work"
|
||||||
|
android:order="103"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="auto_sync_personal_account_data"
|
android:key="auto_sync_personal_account_data"
|
||||||
android:title="@string/account_settings_menu_auto_sync_personal" />
|
android:title="@string/account_settings_menu_auto_sync_personal"
|
||||||
|
android:order="104"/>
|
||||||
|
|
||||||
<com.android.settingslib.RestrictedSwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="add_users_when_locked"
|
android:key="add_users_when_locked"
|
||||||
android:title="@string/user_add_on_lockscreen_menu"
|
android:title="@string/user_add_on_lockscreen_menu"
|
||||||
android:summary="@string/user_add_on_lockscreen_menu_summary"
|
android:summary="@string/user_add_on_lockscreen_menu_summary"
|
||||||
settings:useAdditionalSummary="true" />
|
settings:useAdditionalSummary="true"
|
||||||
|
android:order="105"/>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
104
src/com/android/settings/accounts/AccountPreference.java
Normal file
104
src/com/android/settings/accounts/AccountPreference.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.graphics.drawable.Drawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.Preference.OnPreferenceClickListener;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
|
||||||
|
import static android.content.Intent.EXTRA_USER;
|
||||||
|
|
||||||
|
public class AccountPreference extends Preference implements OnPreferenceClickListener {
|
||||||
|
/**
|
||||||
|
* Title of the tile that is shown to the user.
|
||||||
|
* @attr ref android.R.styleable#PreferenceHeader_title
|
||||||
|
*/
|
||||||
|
private final CharSequence mTitle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packange name used to resolve the resources of the title shown to the user in the new
|
||||||
|
* fragment.
|
||||||
|
*/
|
||||||
|
private final String mTitleResPackageName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource id of the title shown to the user in the new fragment.
|
||||||
|
*/
|
||||||
|
private final int mTitleResId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full class name of the fragment to display when this tile is
|
||||||
|
* selected.
|
||||||
|
* @attr ref android.R.styleable#PreferenceHeader_fragment
|
||||||
|
*/
|
||||||
|
private final String mFragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional arguments to supply to the fragment when it is
|
||||||
|
* instantiated.
|
||||||
|
*/
|
||||||
|
private final Bundle mFragmentArguments;
|
||||||
|
|
||||||
|
public AccountPreference(Context context, CharSequence title, String titleResPackageName,
|
||||||
|
int titleResId, String fragment, Bundle fragmentArguments, Drawable icon) {
|
||||||
|
super(context);
|
||||||
|
mTitle = title;
|
||||||
|
mTitleResPackageName = titleResPackageName;
|
||||||
|
mTitleResId = titleResId;
|
||||||
|
mFragment = fragment;
|
||||||
|
mFragmentArguments = fragmentArguments;
|
||||||
|
setWidgetLayoutResource(R.layout.account_type_preference);
|
||||||
|
|
||||||
|
setTitle(title);
|
||||||
|
setIcon(icon);
|
||||||
|
|
||||||
|
setOnPreferenceClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
if (mFragment != null) {
|
||||||
|
UserManager userManager =
|
||||||
|
(UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||||
|
UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER);
|
||||||
|
if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), userManager,
|
||||||
|
user.getIdentifier())) {
|
||||||
|
return true;
|
||||||
|
} else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(),
|
||||||
|
user.getIdentifier())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
|
||||||
|
null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
|
||||||
|
mTitleResId, null /* title */);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getitle() {
|
||||||
|
return mTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,552 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.Preference.OnPreferenceClickListener;
|
||||||
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.settings.AccessiblePreferenceCategory;
|
||||||
|
import com.android.settings.DimmableIconPreference;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.core.PreferenceController;
|
||||||
|
import com.android.settings.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settings.core.lifecycle.events.OnPause;
|
||||||
|
import com.android.settings.core.lifecycle.events.OnResume;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settings.search.Index;
|
||||||
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
|
import com.android.settingslib.RestrictedPreference;
|
||||||
|
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static android.content.Intent.EXTRA_USER;
|
||||||
|
import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
||||||
|
import static android.os.UserManager.DISALLOW_REMOVE_USER;
|
||||||
|
import static android.provider.Settings.EXTRA_AUTHORITIES;
|
||||||
|
|
||||||
|
public class AccountPreferenceController extends PreferenceController
|
||||||
|
implements AuthenticatorHelper.OnAccountsUpdateListener,
|
||||||
|
OnPreferenceClickListener, LifecycleObserver, OnPause, OnResume {
|
||||||
|
|
||||||
|
private static final String TAG = "AccountPrefController";
|
||||||
|
private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS";
|
||||||
|
|
||||||
|
private static final int ORDER_ACCOUNT_PROFILES = 1;
|
||||||
|
private static final int ORDER_LAST = 1002;
|
||||||
|
private static final int ORDER_NEXT_TO_LAST = 1001;
|
||||||
|
private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000;
|
||||||
|
|
||||||
|
private UserManager mUm;
|
||||||
|
private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
|
||||||
|
private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver
|
||||||
|
= new ManagedProfileBroadcastReceiver();
|
||||||
|
private Preference mProfileNotAvailablePreference;
|
||||||
|
private String[] mAuthorities;
|
||||||
|
private int mAuthoritiesCount = 0;
|
||||||
|
private PreferenceFragment mParent;
|
||||||
|
private boolean mIAEnabled;
|
||||||
|
private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
|
||||||
|
private AccountRestrictionHelper mHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds data related to the accounts belonging to one profile.
|
||||||
|
*/
|
||||||
|
public static class ProfileData {
|
||||||
|
/**
|
||||||
|
* The preference that displays the accounts.
|
||||||
|
*/
|
||||||
|
public PreferenceGroup preferenceGroup;
|
||||||
|
/**
|
||||||
|
* The preference that displays the add account button.
|
||||||
|
*/
|
||||||
|
public DimmableIconPreference addAccountPreference;
|
||||||
|
/**
|
||||||
|
* The preference that displays the button to remove the managed profile
|
||||||
|
*/
|
||||||
|
public RestrictedPreference removeWorkProfilePreference;
|
||||||
|
/**
|
||||||
|
* The preference that displays managed profile settings.
|
||||||
|
*/
|
||||||
|
public Preference managedProfilePreference;
|
||||||
|
/**
|
||||||
|
* The {@link AuthenticatorHelper} that holds accounts data for this profile.
|
||||||
|
*/
|
||||||
|
public AuthenticatorHelper authenticatorHelper;
|
||||||
|
/**
|
||||||
|
* The {@link UserInfo} of the profile.
|
||||||
|
*/
|
||||||
|
public UserInfo userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountPreferenceController(Context context, PreferenceFragment parent,
|
||||||
|
String[] authorities) {
|
||||||
|
this(context, parent, authorities, new AccountRestrictionHelper(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
AccountPreferenceController(Context context, PreferenceFragment parent,
|
||||||
|
String[] authorities, AccountRestrictionHelper helper) {
|
||||||
|
super(context);
|
||||||
|
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||||
|
mAuthorities = authorities;
|
||||||
|
mParent = parent;
|
||||||
|
if (mAuthorities != null) {
|
||||||
|
mAuthoritiesCount = mAuthorities.length;
|
||||||
|
}
|
||||||
|
mIAEnabled = FeatureFactory.getFactory(mContext).getDashboardFeatureProvider(mContext)
|
||||||
|
.isEnabled();
|
||||||
|
mHelper = helper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return !mUm.isManagedProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||||
|
if (!isAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Resources res = mContext.getResources();
|
||||||
|
final String screenTitle = res.getString(R.string.account_settings_title);
|
||||||
|
|
||||||
|
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
|
||||||
|
final int profilesCount = profiles.size();
|
||||||
|
for (int i = 0; i < profilesCount; i++) {
|
||||||
|
UserInfo userInfo = profiles.get(i);
|
||||||
|
if (userInfo.isEnabled()) {
|
||||||
|
if (!mHelper.hasBaseUserRestriction(DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) {
|
||||||
|
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||||
|
data.title = res.getString(R.string.add_account_label);
|
||||||
|
data.screenTitle = screenTitle;
|
||||||
|
rawData.add(data);
|
||||||
|
}
|
||||||
|
if (userInfo.isManagedProfile()) {
|
||||||
|
if (!mHelper.hasBaseUserRestriction(DISALLOW_REMOVE_USER,
|
||||||
|
UserHandle.myUserId())) {
|
||||||
|
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||||
|
data.title = res.getString(R.string.remove_managed_profile_label);
|
||||||
|
data.screenTitle = screenTitle;
|
||||||
|
rawData.add(data);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||||
|
data.title = res.getString(R.string.managed_profile_settings_title);
|
||||||
|
data.screenTitle = screenTitle;
|
||||||
|
rawData.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
cleanUpPreferences();
|
||||||
|
updateUi();
|
||||||
|
mManagedProfileBroadcastReceiver.register(mContext);
|
||||||
|
listenToAccountUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
stopListeningToAccountUpdates();
|
||||||
|
mManagedProfileBroadcastReceiver.unregister(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccountsUpdate(UserHandle userHandle) {
|
||||||
|
final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
|
||||||
|
if (profileData != null) {
|
||||||
|
updateAccountTypes(profileData);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
// Check the preference
|
||||||
|
final int count = mProfiles.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
ProfileData profileData = mProfiles.valueAt(i);
|
||||||
|
if (preference == profileData.addAccountPreference) {
|
||||||
|
Intent intent = new Intent(ADD_ACCOUNT_ACTION);
|
||||||
|
intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
|
||||||
|
intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (preference == profileData.removeWorkProfilePreference) {
|
||||||
|
final int userId = profileData.userInfo.id;
|
||||||
|
RemoveUserFragment.newInstance(userId).show(mParent.getFragmentManager(),
|
||||||
|
"removeUser");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (preference == profileData.managedProfilePreference) {
|
||||||
|
Bundle arguments = new Bundle();
|
||||||
|
arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle());
|
||||||
|
((SettingsActivity) mParent.getActivity()).startPreferencePanel(
|
||||||
|
ManagedProfileSettings.class.getName(), arguments,
|
||||||
|
R.string.managed_profile_settings_title, null, null, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SparseArray<ProfileData> getProfileData() {
|
||||||
|
return mProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUi() {
|
||||||
|
if (!mIAEnabled) {
|
||||||
|
// Load the preferences from an XML resource
|
||||||
|
mParent.addPreferencesFromResource(R.xml.account_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAvailable()) {
|
||||||
|
// This should not happen
|
||||||
|
Log.e(TAG, "We should not be showing settings for a managed profile");
|
||||||
|
if (!mIAEnabled) {
|
||||||
|
((AccountSettings) mParent).finish();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUm.isLinkedUser()) {
|
||||||
|
// Restricted user or similar
|
||||||
|
UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
|
||||||
|
updateProfileUi(userInfo);
|
||||||
|
} else {
|
||||||
|
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
|
||||||
|
final int profilesCount = profiles.size();
|
||||||
|
final boolean addCategory = profilesCount > 1;
|
||||||
|
for (int i = 0; i < profilesCount; i++) {
|
||||||
|
updateProfileUi(profiles.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all preferences, starting with one for the primary profile.
|
||||||
|
// Note that we're relying on the ordering given by the SparseArray keys, and on the
|
||||||
|
// value of UserHandle.USER_OWNER being smaller than all the rest.
|
||||||
|
final int profilesCount = mProfiles.size();
|
||||||
|
for (int i = 0; i < profilesCount; i++) {
|
||||||
|
updateAccountTypes(mProfiles.valueAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProfileUi(final UserInfo userInfo) {
|
||||||
|
final Context context = mContext;
|
||||||
|
final ProfileData profileData = new ProfileData();
|
||||||
|
profileData.userInfo = userInfo;
|
||||||
|
AccessiblePreferenceCategory preferenceGroup =
|
||||||
|
mHelper.createAccessiblePreferenceCategory(mParent.getPreferenceManager().getContext());
|
||||||
|
preferenceGroup.setOrder(mAccountProfileOrder++);
|
||||||
|
if (isSingleProfile()) {
|
||||||
|
preferenceGroup.setTitle(R.string.account_for_section_header);
|
||||||
|
preferenceGroup.setContentDescription(
|
||||||
|
mContext.getString(R.string.account_settings));
|
||||||
|
} else if (userInfo.isManagedProfile()) {
|
||||||
|
preferenceGroup.setLayoutResource(R.layout.work_profile_category);
|
||||||
|
preferenceGroup.setTitle(R.string.category_work);
|
||||||
|
String workGroupSummary = getWorkGroupSummary(context, userInfo);
|
||||||
|
preferenceGroup.setSummary(workGroupSummary);
|
||||||
|
preferenceGroup.setContentDescription(
|
||||||
|
mContext.getString(R.string.accessibility_category_work, workGroupSummary));
|
||||||
|
profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference(context);
|
||||||
|
mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
|
||||||
|
DISALLOW_REMOVE_USER, UserHandle.myUserId());
|
||||||
|
profileData.managedProfilePreference = newManagedProfileSettings();
|
||||||
|
} else {
|
||||||
|
preferenceGroup.setTitle(R.string.category_personal);
|
||||||
|
preferenceGroup.setContentDescription(
|
||||||
|
mContext.getString(R.string.accessibility_category_personal));
|
||||||
|
}
|
||||||
|
mParent.getPreferenceScreen().addPreference(preferenceGroup);
|
||||||
|
profileData.preferenceGroup = preferenceGroup;
|
||||||
|
if (userInfo.isEnabled()) {
|
||||||
|
profileData.authenticatorHelper = new AuthenticatorHelper(context,
|
||||||
|
userInfo.getUserHandle(), this);
|
||||||
|
profileData.addAccountPreference = newAddAccountPreference(context);
|
||||||
|
mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
|
||||||
|
DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
|
||||||
|
}
|
||||||
|
mProfiles.put(userInfo.id, profileData);
|
||||||
|
Index.getInstance(mContext).updateFromClassNameResource(
|
||||||
|
AccountSettings.class.getName(), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DimmableIconPreference newAddAccountPreference(Context context) {
|
||||||
|
DimmableIconPreference preference =
|
||||||
|
new DimmableIconPreference(mParent.getPreferenceManager().getContext());
|
||||||
|
preference.setTitle(R.string.add_account_label);
|
||||||
|
preference.setIcon(R.drawable.ic_menu_add);
|
||||||
|
preference.setOnPreferenceClickListener(this);
|
||||||
|
preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestrictedPreference newRemoveWorkProfilePreference(Context context) {
|
||||||
|
RestrictedPreference preference = new RestrictedPreference(
|
||||||
|
mParent.getPreferenceManager().getContext());
|
||||||
|
preference.setTitle(R.string.remove_managed_profile_label);
|
||||||
|
preference.setIcon(R.drawable.ic_menu_delete);
|
||||||
|
preference.setOnPreferenceClickListener(this);
|
||||||
|
preference.setOrder(ORDER_LAST);
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Preference newManagedProfileSettings() {
|
||||||
|
Preference preference = new Preference(mParent.getPreferenceManager().getContext());
|
||||||
|
preference.setTitle(R.string.managed_profile_settings_title);
|
||||||
|
preference.setIcon(R.drawable.ic_settings);
|
||||||
|
preference.setOnPreferenceClickListener(this);
|
||||||
|
preference.setOrder(ORDER_NEXT_TO_LAST);
|
||||||
|
return preference;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWorkGroupSummary(Context context, UserInfo userInfo) {
|
||||||
|
PackageManager packageManager = context.getPackageManager();
|
||||||
|
ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
|
||||||
|
if (adminApplicationInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
|
||||||
|
return mContext.getString(R.string.managing_admin, appLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanUpPreferences() {
|
||||||
|
PreferenceScreen screen = mParent.getPreferenceScreen();
|
||||||
|
for (int i = 0; i < mProfiles.size(); i++) {
|
||||||
|
final PreferenceGroup preferenceGroup = mProfiles.valueAt(i).preferenceGroup;
|
||||||
|
screen.removePreference(preferenceGroup);
|
||||||
|
}
|
||||||
|
mProfiles.clear();
|
||||||
|
mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void listenToAccountUpdates() {
|
||||||
|
final int count = mProfiles.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
||||||
|
if (authenticatorHelper != null) {
|
||||||
|
authenticatorHelper.listenToAccountUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopListeningToAccountUpdates() {
|
||||||
|
final int count = mProfiles.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
||||||
|
if (authenticatorHelper != null) {
|
||||||
|
authenticatorHelper.stopListeningToAccountUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAccountTypes(ProfileData profileData) {
|
||||||
|
profileData.preferenceGroup.removeAll();
|
||||||
|
if (profileData.userInfo.isEnabled()) {
|
||||||
|
final ArrayList<AccountPreference> preferences = getAccountTypePreferences(
|
||||||
|
profileData.authenticatorHelper, profileData.userInfo.getUserHandle());
|
||||||
|
final int count = preferences.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
profileData.preferenceGroup.addPreference(preferences.get(i));
|
||||||
|
}
|
||||||
|
if (profileData.addAccountPreference != null) {
|
||||||
|
profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Put a label instead of the accounts list
|
||||||
|
if (mProfileNotAvailablePreference == null) {
|
||||||
|
mProfileNotAvailablePreference =
|
||||||
|
new Preference(mParent.getPreferenceManager().getContext());
|
||||||
|
}
|
||||||
|
mProfileNotAvailablePreference.setEnabled(false);
|
||||||
|
mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
|
||||||
|
mProfileNotAvailablePreference.setTitle(null);
|
||||||
|
mProfileNotAvailablePreference.setSummary(
|
||||||
|
R.string.managed_profile_not_available_label);
|
||||||
|
profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
|
||||||
|
}
|
||||||
|
if (profileData.removeWorkProfilePreference != null) {
|
||||||
|
profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
|
||||||
|
}
|
||||||
|
if (profileData.managedProfilePreference != null) {
|
||||||
|
profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper,
|
||||||
|
UserHandle userHandle) {
|
||||||
|
final String[] accountTypes = helper.getEnabledAccountTypes();
|
||||||
|
final ArrayList<AccountPreference> accountTypePreferences =
|
||||||
|
new ArrayList<AccountPreference>(accountTypes.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < accountTypes.length; i++) {
|
||||||
|
final String accountType = accountTypes[i];
|
||||||
|
// Skip showing any account that does not have any of the requested authorities
|
||||||
|
if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final CharSequence label = helper.getLabelForType(mContext, accountType);
|
||||||
|
if (label == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final String titleResPackageName = helper.getPackageForType(accountType);
|
||||||
|
final int titleResId = helper.getLabelIdForType(accountType);
|
||||||
|
|
||||||
|
final Account[] accounts = AccountManager.get(mContext)
|
||||||
|
.getAccountsByTypeAsUser(accountType, userHandle);
|
||||||
|
final boolean skipToAccount = accounts.length == 1
|
||||||
|
&& !helper.hasAccountPreferences(accountType);
|
||||||
|
|
||||||
|
if (skipToAccount) {
|
||||||
|
final Bundle fragmentArguments = new Bundle();
|
||||||
|
fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
|
||||||
|
accounts[0]);
|
||||||
|
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
|
||||||
|
|
||||||
|
accountTypePreferences.add(new AccountPreference(
|
||||||
|
mParent.getPreferenceManager().getContext(), label, titleResPackageName,
|
||||||
|
titleResId, AccountSyncSettings.class.getName(), fragmentArguments,
|
||||||
|
helper.getDrawableForType(mContext, accountType)));
|
||||||
|
} else {
|
||||||
|
final Bundle fragmentArguments = new Bundle();
|
||||||
|
fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
|
||||||
|
fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
|
||||||
|
label.toString());
|
||||||
|
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
|
||||||
|
|
||||||
|
accountTypePreferences.add(new AccountPreference(
|
||||||
|
mParent.getPreferenceManager().getContext(), label, titleResPackageName,
|
||||||
|
titleResId, ManageAccountsSettings.class.getName(), fragmentArguments,
|
||||||
|
helper.getDrawableForType(mContext, accountType)));
|
||||||
|
}
|
||||||
|
helper.preloadDrawableForType(mContext, accountType);
|
||||||
|
}
|
||||||
|
// Sort by label
|
||||||
|
Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() {
|
||||||
|
@Override
|
||||||
|
public int compare(AccountPreference t1, AccountPreference t2) {
|
||||||
|
return t1.getitle().toString().compareTo(t2.getitle().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return accountTypePreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
|
||||||
|
String accountType) {
|
||||||
|
if (mAuthoritiesCount == 0) {
|
||||||
|
// No authorities required
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
|
||||||
|
accountType);
|
||||||
|
if (authoritiesForType == null) {
|
||||||
|
Log.d(TAG, "No sync authorities for account type: " + accountType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < mAuthoritiesCount; j++) {
|
||||||
|
if (authoritiesForType.contains(mAuthorities[j])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSingleProfile() {
|
||||||
|
return mUm.isLinkedUser() || mUm.getProfiles(UserHandle.myUserId()).size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
private boolean mListeningToManagedProfileEvents;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
final String action = intent.getAction();
|
||||||
|
Log.v(TAG, "Received broadcast: " + action);
|
||||||
|
if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
|
||||||
|
|| action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
|
||||||
|
// Clean old state
|
||||||
|
stopListeningToAccountUpdates();
|
||||||
|
cleanUpPreferences();
|
||||||
|
// Build new state
|
||||||
|
updateUi();
|
||||||
|
listenToAccountUpdates();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Context context) {
|
||||||
|
if (!mListeningToManagedProfileEvents) {
|
||||||
|
IntentFilter intentFilter = new IntentFilter();
|
||||||
|
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
|
||||||
|
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
|
||||||
|
context.registerReceiver(this, intentFilter);
|
||||||
|
mListeningToManagedProfileEvents = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister(Context context) {
|
||||||
|
if (mListeningToManagedProfileEvents) {
|
||||||
|
context.unregisterReceiver(this);
|
||||||
|
mListeningToManagedProfileEvents = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.annotation.UserIdInt;
|
||||||
|
import android.content.Context;
|
||||||
|
import com.android.settings.AccessiblePreferenceCategory;
|
||||||
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.RestrictedPreference;
|
||||||
|
|
||||||
|
public class AccountRestrictionHelper {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public AccountRestrictionHelper(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the UI of the preference by checking user restriction.
|
||||||
|
* @param preference The preference we are configuring.
|
||||||
|
* @param userRestriction The user restriction related to the preference.
|
||||||
|
* @param userId The user that we retrieve user restriction of.
|
||||||
|
*/
|
||||||
|
public void enforceRestrictionOnPreference(RestrictedPreference preference,
|
||||||
|
String userRestriction, @UserIdInt int userId) {
|
||||||
|
if (preference == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hasBaseUserRestriction(userRestriction, userId)) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
preference.checkRestrictionAndSetDisabled(userRestriction, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasBaseUserRestriction(String userRestriction, @UserIdInt int userId) {
|
||||||
|
return RestrictedLockUtils.hasBaseUserRestriction(mContext, userRestriction, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessiblePreferenceCategory createAccessiblePreferenceCategory(Context context) {
|
||||||
|
return new AccessiblePreferenceCategory(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -16,32 +16,13 @@
|
|||||||
|
|
||||||
package com.android.settings.accounts;
|
package com.android.settings.accounts;
|
||||||
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.annotation.UserIdInt;
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.UserInfo;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
|
||||||
import android.provider.SearchIndexableResource;
|
import android.provider.SearchIndexableResource;
|
||||||
import android.support.v7.preference.Preference;
|
|
||||||
import android.support.v7.preference.Preference.OnPreferenceClickListener;
|
|
||||||
import android.support.v7.preference.PreferenceGroup;
|
|
||||||
import android.support.v7.preference.PreferenceScreen;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -49,31 +30,16 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.AccessiblePreferenceCategory;
|
|
||||||
import com.android.settings.DimmableIconPreference;
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Index;
|
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settings.search.SearchIndexableRaw;
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
import com.android.settings.users.UserDialogs;
|
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
|
||||||
import com.android.settingslib.RestrictedPreference;
|
|
||||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.content.Intent.EXTRA_USER;
|
|
||||||
import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
|
|
||||||
import static android.os.UserManager.DISALLOW_REMOVE_USER;
|
|
||||||
import static android.provider.Settings.EXTRA_AUTHORITIES;
|
import static android.provider.Settings.EXTRA_AUTHORITIES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,57 +49,13 @@ import static android.provider.Settings.EXTRA_AUTHORITIES;
|
|||||||
* 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 AccountSettings extends SettingsPreferenceFragment
|
public class AccountSettings extends SettingsPreferenceFragment implements Indexable {
|
||||||
implements AuthenticatorHelper.OnAccountsUpdateListener,
|
|
||||||
OnPreferenceClickListener, Indexable {
|
|
||||||
public static final String TAG = "AccountSettings";
|
public static final String TAG = "AccountSettings";
|
||||||
|
|
||||||
private static final String KEY_ACCOUNT = "account";
|
|
||||||
|
|
||||||
private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS";
|
|
||||||
private static final String TAG_CONFIRM_AUTO_SYNC_CHANGE = "confirmAutoSyncChange";
|
|
||||||
|
|
||||||
private static final int ORDER_LAST = 1002;
|
|
||||||
private static final int ORDER_NEXT_TO_LAST = 1001;
|
|
||||||
private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000;
|
|
||||||
|
|
||||||
private UserManager mUm;
|
|
||||||
private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
|
|
||||||
private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver
|
|
||||||
= new ManagedProfileBroadcastReceiver();
|
|
||||||
private Preference mProfileNotAvailablePreference;
|
|
||||||
private String[] mAuthorities;
|
private String[] mAuthorities;
|
||||||
private int mAuthoritiesCount = 0;
|
|
||||||
|
|
||||||
/**
|
private AccountPreferenceController mAccountPreferenceController;
|
||||||
* Holds data related to the accounts belonging to one profile.
|
|
||||||
*/
|
|
||||||
public static class ProfileData {
|
|
||||||
/**
|
|
||||||
* The preference that displays the accounts.
|
|
||||||
*/
|
|
||||||
public PreferenceGroup preferenceGroup;
|
|
||||||
/**
|
|
||||||
* The preference that displays the add account button.
|
|
||||||
*/
|
|
||||||
public DimmableIconPreference addAccountPreference;
|
|
||||||
/**
|
|
||||||
* The preference that displays the button to remove the managed profile
|
|
||||||
*/
|
|
||||||
public RestrictedPreference removeWorkProfilePreference;
|
|
||||||
/**
|
|
||||||
* The preference that displays managed profile settings.
|
|
||||||
*/
|
|
||||||
public Preference managedProfilePreference;
|
|
||||||
/**
|
|
||||||
* The {@link AuthenticatorHelper} that holds accounts data for this profile.
|
|
||||||
*/
|
|
||||||
public AuthenticatorHelper authenticatorHelper;
|
|
||||||
/**
|
|
||||||
* The {@link UserInfo} of the profile.
|
|
||||||
*/
|
|
||||||
public UserInfo userInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -143,13 +65,11 @@ public class AccountSettings extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
mUm = (UserManager) getSystemService(Context.USER_SERVICE);
|
|
||||||
mProfileNotAvailablePreference = new Preference(getPrefContext());
|
|
||||||
mAuthorities = getActivity().getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
|
mAuthorities = getActivity().getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
|
||||||
if (mAuthorities != null) {
|
|
||||||
mAuthoritiesCount = mAuthorities.length;
|
|
||||||
}
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
mAccountPreferenceController =
|
||||||
|
new AccountPreferenceController(getActivity(), this, mAuthorities);
|
||||||
|
getLifecycle().addObserver(mAccountPreferenceController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -161,461 +81,34 @@ public class AccountSettings extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onPrepareOptionsMenu(Menu menu) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
final UserHandle currentProfile = Process.myUserHandle();
|
final UserHandle currentProfile = Process.myUserHandle();
|
||||||
if (mProfiles.size() == 1) {
|
SparseArray<AccountPreferenceController.ProfileData> profiles =
|
||||||
|
mAccountPreferenceController.getProfileData();
|
||||||
|
|
||||||
|
if (profiles.size() == 1) {
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync)
|
menu.findItem(R.id.account_settings_menu_auto_sync)
|
||||||
.setVisible(true)
|
.setVisible(true)
|
||||||
.setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
|
.setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
|
||||||
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
||||||
currentProfile.getIdentifier()));
|
currentProfile.getIdentifier()));
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync_personal).setVisible(false);
|
menu.findItem(R.id.account_settings_menu_auto_sync_personal).setVisible(false);
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync_work).setVisible(false);
|
menu.findItem(R.id.account_settings_menu_auto_sync_work).setVisible(false);
|
||||||
} else if (mProfiles.size() > 1) {
|
} else if (profiles.size() > 1) {
|
||||||
// We assume there's only one managed profile, otherwise UI needs to change
|
// We assume there's only one managed profile, otherwise UI needs to change
|
||||||
final UserHandle managedProfile = mProfiles.valueAt(1).userInfo.getUserHandle();
|
final UserHandle managedProfile = profiles.valueAt(1).userInfo.getUserHandle();
|
||||||
|
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync_personal)
|
menu.findItem(R.id.account_settings_menu_auto_sync_personal)
|
||||||
.setVisible(true)
|
.setVisible(true)
|
||||||
.setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
|
.setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile))
|
||||||
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
||||||
currentProfile.getIdentifier()));
|
currentProfile.getIdentifier()));
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync_work)
|
menu.findItem(R.id.account_settings_menu_auto_sync_work)
|
||||||
.setVisible(true)
|
.setVisible(true)
|
||||||
.setOnMenuItemClickListener(new MasterSyncStateClickListener(managedProfile))
|
.setOnMenuItemClickListener(new MasterSyncStateClickListener(managedProfile))
|
||||||
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
.setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser(
|
||||||
managedProfile.getIdentifier()));
|
managedProfile.getIdentifier()));
|
||||||
menu.findItem(R.id.account_settings_menu_auto_sync).setVisible(false);
|
menu.findItem(R.id.account_settings_menu_auto_sync).setVisible(false);
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Method onPrepareOptionsMenu called before mProfiles was initialized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
cleanUpPreferences();
|
|
||||||
updateUi();
|
|
||||||
mManagedProfileBroadcastReceiver.register(getActivity());
|
|
||||||
listenToAccountUpdates();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
stopListeningToAccountUpdates();
|
|
||||||
mManagedProfileBroadcastReceiver.unregister(getActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAccountsUpdate(UserHandle userHandle) {
|
|
||||||
final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
|
|
||||||
if (profileData != null) {
|
|
||||||
updateAccountTypes(profileData);
|
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
|
Log.w(TAG, "Method onPrepareOptionsMenu called before profiles was initialized");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
|
||||||
// Check the preference
|
|
||||||
final int count = mProfiles.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
ProfileData profileData = mProfiles.valueAt(i);
|
|
||||||
if (preference == profileData.addAccountPreference) {
|
|
||||||
Intent intent = new Intent(ADD_ACCOUNT_ACTION);
|
|
||||||
intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
|
|
||||||
intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (preference == profileData.removeWorkProfilePreference) {
|
|
||||||
final int userId = profileData.userInfo.id;
|
|
||||||
RemoveUserFragment.newInstance(userId).show(getActivity().getFragmentManager(),
|
|
||||||
"removeUser");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (preference == profileData.managedProfilePreference) {
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle());
|
|
||||||
((SettingsActivity) getActivity()).startPreferencePanel(
|
|
||||||
ManagedProfileSettings.class.getName(), arguments,
|
|
||||||
R.string.managed_profile_settings_title, null, null, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateUi() {
|
|
||||||
// Load the preferences from an XML resource
|
|
||||||
addPreferencesFromResource(R.xml.account_settings);
|
|
||||||
|
|
||||||
if (mUm.isManagedProfile()) {
|
|
||||||
// This should not happen
|
|
||||||
Log.e(TAG, "We should not be showing settings for a managed profile");
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference(KEY_ACCOUNT);
|
|
||||||
if(mUm.isLinkedUser()) {
|
|
||||||
// Restricted user or similar
|
|
||||||
UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
|
|
||||||
updateProfileUi(userInfo, false /* no category needed */, preferenceScreen);
|
|
||||||
} else {
|
|
||||||
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
|
|
||||||
final int profilesCount = profiles.size();
|
|
||||||
final boolean addCategory = profilesCount > 1;
|
|
||||||
for (int i = 0; i < profilesCount; i++) {
|
|
||||||
updateProfileUi(profiles.get(i), addCategory, preferenceScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all preferences, starting with one for the primary profile.
|
|
||||||
// Note that we're relying on the ordering given by the SparseArray keys, and on the
|
|
||||||
// value of UserHandle.USER_OWNER being smaller than all the rest.
|
|
||||||
final int profilesCount = mProfiles.size();
|
|
||||||
for (int i = 0; i < profilesCount; i++) {
|
|
||||||
ProfileData profileData = mProfiles.valueAt(i);
|
|
||||||
if (!profileData.preferenceGroup.equals(preferenceScreen)) {
|
|
||||||
preferenceScreen.addPreference(profileData.preferenceGroup);
|
|
||||||
}
|
|
||||||
updateAccountTypes(profileData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateProfileUi(final UserInfo userInfo, boolean addCategory,
|
|
||||||
PreferenceScreen parent) {
|
|
||||||
final Context context = getActivity();
|
|
||||||
final ProfileData profileData = new ProfileData();
|
|
||||||
profileData.userInfo = userInfo;
|
|
||||||
if (addCategory) {
|
|
||||||
profileData.preferenceGroup = new AccessiblePreferenceCategory(getPrefContext());
|
|
||||||
if (userInfo.isManagedProfile()) {
|
|
||||||
profileData.preferenceGroup.setLayoutResource(R.layout.work_profile_category);
|
|
||||||
profileData.preferenceGroup.setTitle(R.string.category_work);
|
|
||||||
String workGroupSummary = getWorkGroupSummary(context, userInfo);
|
|
||||||
profileData.preferenceGroup.setSummary(workGroupSummary);
|
|
||||||
((AccessiblePreferenceCategory) profileData.preferenceGroup).setContentDescription(
|
|
||||||
getString(R.string.accessibility_category_work, workGroupSummary));
|
|
||||||
profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference(context);
|
|
||||||
enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
|
|
||||||
DISALLOW_REMOVE_USER, UserHandle.myUserId());
|
|
||||||
profileData.managedProfilePreference = newManagedProfileSettings();
|
|
||||||
} else {
|
|
||||||
profileData.preferenceGroup.setTitle(R.string.category_personal);
|
|
||||||
((AccessiblePreferenceCategory) profileData.preferenceGroup).setContentDescription(
|
|
||||||
getString(R.string.accessibility_category_personal));
|
|
||||||
}
|
|
||||||
parent.addPreference(profileData.preferenceGroup);
|
|
||||||
} else {
|
|
||||||
profileData.preferenceGroup = parent;
|
|
||||||
}
|
|
||||||
if (userInfo.isEnabled()) {
|
|
||||||
profileData.authenticatorHelper = new AuthenticatorHelper(context,
|
|
||||||
userInfo.getUserHandle(), this);
|
|
||||||
profileData.addAccountPreference = newAddAccountPreference(context);
|
|
||||||
enforceRestrictionOnPreference(profileData.addAccountPreference,
|
|
||||||
DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
|
|
||||||
}
|
|
||||||
mProfiles.put(userInfo.id, profileData);
|
|
||||||
Index.getInstance(getActivity()).updateFromClassNameResource(
|
|
||||||
AccountSettings.class.getName(), true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the UI of the preference by checking user restriction.
|
|
||||||
* @param preference The preference we are configuring.
|
|
||||||
* @param userRestriction The user restriction related to the preference.
|
|
||||||
* @param userId The user that we retrieve user restriction of.
|
|
||||||
*/
|
|
||||||
private void enforceRestrictionOnPreference(RestrictedPreference preference,
|
|
||||||
String userRestriction, @UserIdInt int userId) {
|
|
||||||
if (RestrictedLockUtils.hasBaseUserRestriction(getActivity(), userRestriction, userId)) {
|
|
||||||
preference.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
preference.checkRestrictionAndSetDisabled(userRestriction, userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DimmableIconPreference newAddAccountPreference(Context context) {
|
|
||||||
DimmableIconPreference preference = new DimmableIconPreference(getPrefContext());
|
|
||||||
preference.setTitle(R.string.add_account_label);
|
|
||||||
preference.setIcon(R.drawable.ic_menu_add);
|
|
||||||
preference.setOnPreferenceClickListener(this);
|
|
||||||
preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
|
|
||||||
return preference;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RestrictedPreference newRemoveWorkProfilePreference(Context context) {
|
|
||||||
RestrictedPreference preference = new RestrictedPreference(getPrefContext());
|
|
||||||
preference.setTitle(R.string.remove_managed_profile_label);
|
|
||||||
preference.setIcon(R.drawable.ic_menu_delete);
|
|
||||||
preference.setOnPreferenceClickListener(this);
|
|
||||||
preference.setOrder(ORDER_LAST);
|
|
||||||
return preference;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Preference newManagedProfileSettings() {
|
|
||||||
Preference preference = new Preference(getPrefContext());
|
|
||||||
preference.setTitle(R.string.managed_profile_settings_title);
|
|
||||||
preference.setIcon(R.drawable.ic_settings);
|
|
||||||
preference.setOnPreferenceClickListener(this);
|
|
||||||
preference.setOrder(ORDER_NEXT_TO_LAST);
|
|
||||||
return preference;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getWorkGroupSummary(Context context, UserInfo userInfo) {
|
|
||||||
PackageManager packageManager = context.getPackageManager();
|
|
||||||
ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
|
|
||||||
if (adminApplicationInfo == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
|
|
||||||
return getString(R.string.managing_admin, appLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanUpPreferences() {
|
|
||||||
PreferenceScreen preferenceScreen = getPreferenceScreen();
|
|
||||||
if (preferenceScreen != null) {
|
|
||||||
preferenceScreen.removeAll();
|
|
||||||
}
|
|
||||||
mProfiles.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void listenToAccountUpdates() {
|
|
||||||
final int count = mProfiles.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
|
||||||
if (authenticatorHelper != null) {
|
|
||||||
authenticatorHelper.listenToAccountUpdates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopListeningToAccountUpdates() {
|
|
||||||
final int count = mProfiles.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
|
|
||||||
if (authenticatorHelper != null) {
|
|
||||||
authenticatorHelper.stopListeningToAccountUpdates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateAccountTypes(ProfileData profileData) {
|
|
||||||
profileData.preferenceGroup.removeAll();
|
|
||||||
if (profileData.userInfo.isEnabled()) {
|
|
||||||
final ArrayList<AccountPreference> preferences = getAccountTypePreferences(
|
|
||||||
profileData.authenticatorHelper, profileData.userInfo.getUserHandle());
|
|
||||||
final int count = preferences.size();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
profileData.preferenceGroup.addPreference(preferences.get(i));
|
|
||||||
}
|
|
||||||
if (profileData.addAccountPreference != null) {
|
|
||||||
profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Put a label instead of the accounts list
|
|
||||||
mProfileNotAvailablePreference.setEnabled(false);
|
|
||||||
mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
|
|
||||||
mProfileNotAvailablePreference.setTitle(null);
|
|
||||||
mProfileNotAvailablePreference.setSummary(
|
|
||||||
R.string.managed_profile_not_available_label);
|
|
||||||
profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
|
|
||||||
}
|
|
||||||
if (profileData.removeWorkProfilePreference != null) {
|
|
||||||
profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
|
|
||||||
}
|
|
||||||
if (profileData.managedProfilePreference != null) {
|
|
||||||
profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper,
|
|
||||||
UserHandle userHandle) {
|
|
||||||
final String[] accountTypes = helper.getEnabledAccountTypes();
|
|
||||||
final ArrayList<AccountPreference> accountTypePreferences =
|
|
||||||
new ArrayList<AccountPreference>(accountTypes.length);
|
|
||||||
|
|
||||||
for (int i = 0; i < accountTypes.length; i++) {
|
|
||||||
final String accountType = accountTypes[i];
|
|
||||||
// Skip showing any account that does not have any of the requested authorities
|
|
||||||
if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final CharSequence label = helper.getLabelForType(getActivity(), accountType);
|
|
||||||
if (label == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final String titleResPackageName = helper.getPackageForType(accountType);
|
|
||||||
final int titleResId = helper.getLabelIdForType(accountType);
|
|
||||||
|
|
||||||
final Account[] accounts = AccountManager.get(getActivity())
|
|
||||||
.getAccountsByTypeAsUser(accountType, userHandle);
|
|
||||||
final boolean skipToAccount = accounts.length == 1
|
|
||||||
&& !helper.hasAccountPreferences(accountType);
|
|
||||||
|
|
||||||
if (skipToAccount) {
|
|
||||||
final Bundle fragmentArguments = new Bundle();
|
|
||||||
fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
|
|
||||||
accounts[0]);
|
|
||||||
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
|
|
||||||
|
|
||||||
accountTypePreferences.add(new AccountPreference(getPrefContext(), label,
|
|
||||||
titleResPackageName, titleResId, AccountSyncSettings.class.getName(),
|
|
||||||
fragmentArguments,
|
|
||||||
helper.getDrawableForType(getActivity(), accountType)));
|
|
||||||
} else {
|
|
||||||
final Bundle fragmentArguments = new Bundle();
|
|
||||||
fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
|
|
||||||
fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
|
|
||||||
label.toString());
|
|
||||||
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
|
|
||||||
|
|
||||||
accountTypePreferences.add(new AccountPreference(getPrefContext(), label,
|
|
||||||
titleResPackageName, titleResId, ManageAccountsSettings.class.getName(),
|
|
||||||
fragmentArguments,
|
|
||||||
helper.getDrawableForType(getActivity(), accountType)));
|
|
||||||
}
|
|
||||||
helper.preloadDrawableForType(getActivity(), accountType);
|
|
||||||
}
|
|
||||||
// Sort by label
|
|
||||||
Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() {
|
|
||||||
@Override
|
|
||||||
public int compare(AccountPreference t1, AccountPreference t2) {
|
|
||||||
return t1.mTitle.toString().compareTo(t2.mTitle.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return accountTypePreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
|
|
||||||
String accountType) {
|
|
||||||
if (mAuthoritiesCount == 0) {
|
|
||||||
// No authorities required
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
|
|
||||||
accountType);
|
|
||||||
if (authoritiesForType == null) {
|
|
||||||
Log.d(TAG, "No sync authorities for account type: " + accountType);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < mAuthoritiesCount; j++) {
|
|
||||||
if (authoritiesForType.contains(mAuthorities[j])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AccountPreference extends Preference implements OnPreferenceClickListener {
|
|
||||||
/**
|
|
||||||
* Title of the tile that is shown to the user.
|
|
||||||
* @attr ref android.R.styleable#PreferenceHeader_title
|
|
||||||
*/
|
|
||||||
private final CharSequence mTitle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packange name used to resolve the resources of the title shown to the user in the new
|
|
||||||
* fragment.
|
|
||||||
*/
|
|
||||||
private final String mTitleResPackageName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resource id of the title shown to the user in the new fragment.
|
|
||||||
*/
|
|
||||||
private final int mTitleResId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full class name of the fragment to display when this tile is
|
|
||||||
* selected.
|
|
||||||
* @attr ref android.R.styleable#PreferenceHeader_fragment
|
|
||||||
*/
|
|
||||||
private final String mFragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional arguments to supply to the fragment when it is
|
|
||||||
* instantiated.
|
|
||||||
*/
|
|
||||||
private final Bundle mFragmentArguments;
|
|
||||||
|
|
||||||
public AccountPreference(Context context, CharSequence title, String titleResPackageName,
|
|
||||||
int titleResId, String fragment, Bundle fragmentArguments,
|
|
||||||
Drawable icon) {
|
|
||||||
super(context);
|
|
||||||
mTitle = title;
|
|
||||||
mTitleResPackageName = titleResPackageName;
|
|
||||||
mTitleResId = titleResId;
|
|
||||||
mFragment = fragment;
|
|
||||||
mFragmentArguments = fragmentArguments;
|
|
||||||
setWidgetLayoutResource(R.layout.account_type_preference);
|
|
||||||
|
|
||||||
setTitle(title);
|
|
||||||
setIcon(icon);
|
|
||||||
|
|
||||||
setOnPreferenceClickListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
|
||||||
if (mFragment != null) {
|
|
||||||
UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER);
|
|
||||||
if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), mUm,
|
|
||||||
user.getIdentifier())) {
|
|
||||||
return true;
|
|
||||||
} else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(),
|
|
||||||
user.getIdentifier())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
|
|
||||||
null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
|
|
||||||
mTitleResId, null /* title */);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
|
|
||||||
private boolean listeningToManagedProfileEvents;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
final String action = intent.getAction();
|
|
||||||
Log.v(TAG, "Received broadcast: " + action);
|
|
||||||
if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
|
|
||||||
|| action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
|
|
||||||
// Clean old state
|
|
||||||
stopListeningToAccountUpdates();
|
|
||||||
cleanUpPreferences();
|
|
||||||
// Build new state
|
|
||||||
updateUi();
|
|
||||||
listenToAccountUpdates();
|
|
||||||
// Force the menu to update. Note that #onPrepareOptionsMenu uses data built by
|
|
||||||
// #updateUi so we must call this later
|
|
||||||
getActivity().invalidateOptionsMenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register(Context context) {
|
|
||||||
if (!listeningToManagedProfileEvents) {
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
|
||||||
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
|
|
||||||
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
|
|
||||||
context.registerReceiver(this, intentFilter);
|
|
||||||
listeningToManagedProfileEvents = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregister(Context context) {
|
|
||||||
if (listeningToManagedProfileEvents) {
|
|
||||||
context.unregisterReceiver(this);
|
|
||||||
listeningToManagedProfileEvents = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,90 +125,27 @@ public class AccountSettings extends SettingsPreferenceFragment
|
|||||||
Log.d(TAG, "ignoring monkey's attempt to flip sync state");
|
Log.d(TAG, "ignoring monkey's attempt to flip sync state");
|
||||||
} else {
|
} else {
|
||||||
AutoSyncDataPreferenceController.ConfirmAutoSyncChangeFragment.show(
|
AutoSyncDataPreferenceController.ConfirmAutoSyncChangeFragment.show(
|
||||||
AccountSettings.this, !item.isChecked(), mUserHandle, /*preference*/null);
|
AccountSettings.this, !item.isChecked(), mUserHandle, null/*preference*/);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RemoveUserFragment extends InstrumentedDialogFragment {
|
|
||||||
private static final String ARG_USER_ID = "userId";
|
|
||||||
|
|
||||||
static RemoveUserFragment newInstance(int userId) {
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt(ARG_USER_ID, userId);
|
|
||||||
RemoveUserFragment fragment = new RemoveUserFragment();
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
final int userId = getArguments().getInt(ARG_USER_ID);
|
|
||||||
return UserDialogs.createRemoveDialog(getActivity(), userId,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
UserManager um = (UserManager)
|
|
||||||
getActivity().getSystemService(Context.USER_SERVICE);
|
|
||||||
um.removeUser(userId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMetricsCategory() {
|
|
||||||
return MetricsEvent.DIALOG_REMOVE_USER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
new BaseSearchIndexProvider() {
|
new BaseSearchIndexProvider() {
|
||||||
@Override
|
@Override
|
||||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||||
Context context, boolean enabled) {
|
Context context, boolean enabled) {
|
||||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||||
sir.xmlResId = R.xml.account_settings;
|
sir.xmlResId = R.xml.account_settings;
|
||||||
return Arrays.asList(sir);
|
return Arrays.asList(sir);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
|
|
||||||
final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
|
|
||||||
final Resources res = context.getResources();
|
|
||||||
final String screenTitle = res.getString(R.string.account_settings_title);
|
|
||||||
|
|
||||||
final UserManager um = UserManager.get(context);
|
|
||||||
List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId());
|
|
||||||
final int profilesCount = profiles.size();
|
|
||||||
for (int i = 0; i < profilesCount; i++) {
|
|
||||||
UserInfo userInfo = profiles.get(i);
|
|
||||||
if (userInfo.isEnabled()) {
|
|
||||||
if (!RestrictedLockUtils.hasBaseUserRestriction(context,
|
|
||||||
DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) {
|
|
||||||
SearchIndexableRaw data = new SearchIndexableRaw(context);
|
|
||||||
data.title = res.getString(R.string.add_account_label);
|
|
||||||
data.screenTitle = screenTitle;
|
|
||||||
result.add(data);
|
|
||||||
}
|
|
||||||
if (userInfo.isManagedProfile()) {
|
|
||||||
if (!RestrictedLockUtils.hasBaseUserRestriction(context,
|
|
||||||
DISALLOW_REMOVE_USER, UserHandle.myUserId())) {
|
|
||||||
SearchIndexableRaw data = new SearchIndexableRaw(context);
|
|
||||||
data.title = res.getString(R.string.remove_managed_profile_label);
|
|
||||||
data.screenTitle = screenTitle;
|
|
||||||
result.add(data);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
SearchIndexableRaw data = new SearchIndexableRaw(context);
|
|
||||||
data.title = res.getString(R.string.managed_profile_settings_title);
|
|
||||||
data.screenTitle = screenTitle;
|
|
||||||
result.add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
@Override
|
||||||
};
|
public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
|
||||||
|
final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
|
||||||
|
new AccountPreferenceController(context, null, null).updateRawDataToIndex(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -37,11 +37,6 @@ public class EmergencyInfoPreferenceController extends PreferenceController {
|
|||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
|
||||||
super.displayPreference(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||||
if (isAvailable()) {
|
if (isAvailable()) {
|
||||||
|
58
src/com/android/settings/accounts/RemoveUserFragment.java
Normal file
58
src/com/android/settings/accounts/RemoveUserFragment.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.users.UserDialogs;
|
||||||
|
|
||||||
|
class RemoveUserFragment extends InstrumentedDialogFragment {
|
||||||
|
private static final String ARG_USER_ID = "userId";
|
||||||
|
|
||||||
|
static RemoveUserFragment newInstance(int userId) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt(ARG_USER_ID, userId);
|
||||||
|
RemoveUserFragment fragment = new RemoveUserFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final int userId = getArguments().getInt(ARG_USER_ID);
|
||||||
|
return UserDialogs.createRemoveDialog(getActivity(), userId,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
UserManager um = (UserManager)
|
||||||
|
getActivity().getSystemService(Context.USER_SERVICE);
|
||||||
|
um.removeUser(userId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return MetricsEvent.DIALOG_REMOVE_USER;
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,8 @@ import com.android.settingslib.drawer.CategoryKey;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static android.provider.Settings.EXTRA_AUTHORITIES;
|
||||||
|
|
||||||
public class UserAndAccountDashboardFragment extends DashboardFragment {
|
public class UserAndAccountDashboardFragment extends DashboardFragment {
|
||||||
|
|
||||||
private static final String TAG = "UserAndAccountDashboard";
|
private static final String TAG = "UserAndAccountDashboard";
|
||||||
@@ -61,6 +63,11 @@ public class UserAndAccountDashboardFragment extends DashboardFragment {
|
|||||||
controllers.add(new AutoSyncDataPreferenceController(context, this));
|
controllers.add(new AutoSyncDataPreferenceController(context, this));
|
||||||
controllers.add(new AutoSyncPersonalDataPreferenceController(context, this));
|
controllers.add(new AutoSyncPersonalDataPreferenceController(context, this));
|
||||||
controllers.add(new AutoSyncWorkDataPreferenceController(context, this));
|
controllers.add(new AutoSyncWorkDataPreferenceController(context, this));
|
||||||
|
String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
|
||||||
|
final AccountPreferenceController accountPrefController =
|
||||||
|
new AccountPreferenceController(context, this, authorities);
|
||||||
|
getLifecycle().addObserver(accountPrefController);
|
||||||
|
controllers.add(accountPrefController);
|
||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,6 +76,9 @@ public class DashboardDividerDecoration extends RecyclerView.ItemDecoration {
|
|||||||
}
|
}
|
||||||
final PreferenceGroupAdapter prefAdapter = (PreferenceGroupAdapter) adapter;
|
final PreferenceGroupAdapter prefAdapter = (PreferenceGroupAdapter) adapter;
|
||||||
final int adapterPosition = parent.getChildAdapterPosition(view);
|
final int adapterPosition = parent.getChildAdapterPosition(view);
|
||||||
|
if (adapterPosition == RecyclerView.NO_POSITION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final Preference pref = prefAdapter.getItem(adapterPosition);
|
final Preference pref = prefAdapter.getItem(adapterPosition);
|
||||||
final Preference nextPref = prefAdapter.getItem(adapterPosition + 1);
|
final Preference nextPref = prefAdapter.getItem(adapterPosition + 1);
|
||||||
if (nextPref == null) {
|
if (nextPref == null) {
|
||||||
|
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.AuthenticatorDescription;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.settings.AccessiblePreferenceCategory;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.search.SearchIndexableRaw;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowAccountManager;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowContentResolver;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class AccountPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private UserManager mUserManager;
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceFragment mFragment;
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private AccountManager mAccountManager;
|
||||||
|
@Mock(answer = RETURNS_DEEP_STUBS)
|
||||||
|
private AccountRestrictionHelper mAccountHelper;
|
||||||
|
|
||||||
|
private FakeFeatureFactory mFactory;
|
||||||
|
private Context mContext;
|
||||||
|
private AccountPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
ShadowApplication shadowContext = ShadowApplication.getInstance();
|
||||||
|
shadowContext.setSystemService(Context.USER_SERVICE, mUserManager);
|
||||||
|
shadowContext.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
|
||||||
|
mContext = spy(shadowContext.getApplicationContext());
|
||||||
|
FakeFeatureFactory.setupForTest(mContext);
|
||||||
|
mFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||||
|
|
||||||
|
when(mFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
|
||||||
|
when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
|
||||||
|
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
|
||||||
|
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
|
||||||
|
new AuthenticatorDescription[0]);
|
||||||
|
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
|
||||||
|
mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onResume_managedProfile_shouldNotAddAccountCategory() {
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(true);
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, never()).addPreference(any(Preference.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
|
||||||
|
public void onResume_linkedUser_shouldAddOneAccountCategory() {
|
||||||
|
final UserInfo info = new UserInfo(1, "user 1", 0);
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.isLinkedUser()).thenReturn(true);
|
||||||
|
when(mUserManager.getUserInfo(anyInt())).thenReturn(info);
|
||||||
|
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
|
||||||
|
public void onResume_oneProfile_shouldAddOneAccountCategory() {
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", 0));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.isLinkedUser()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
|
||||||
|
public void onResume_twoProfiles_shouldAddTwoAccountCategory() {
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", 0));
|
||||||
|
infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.isLinkedUser()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, times(2)).addPreference(any(PreferenceGroup.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
|
||||||
|
public void onResume_oneProfiles_shouldRemoveOneAccountCategory() {
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.isLinkedUser()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
|
||||||
|
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
|
||||||
|
preferenceGroup);
|
||||||
|
|
||||||
|
// First time resume will build the UI, 2nd time will refresh the UI
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, times(1)).removePreference(any(PreferenceGroup.class));
|
||||||
|
verify(mScreen).removePreference(preferenceGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
|
||||||
|
public void onResume_twoProfiles_shouldRemoveTwoAccountCategory() {
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", 0));
|
||||||
|
infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.isLinkedUser()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
|
||||||
|
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
|
||||||
|
preferenceGroup);
|
||||||
|
|
||||||
|
// First time resume will build the UI, 2nd time will refresh the UI
|
||||||
|
mController.onResume();
|
||||||
|
mController.onResume();
|
||||||
|
|
||||||
|
verify(mScreen, times(2)).removePreference(any(PreferenceGroup.class));
|
||||||
|
verify(mScreen, times(2)).removePreference(preferenceGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_ManagedProfile_shouldNotUpdate() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_DisabledUser_shouldNotUpdate() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_DISABLED));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_EnabledUser_shouldAddOne() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", 0));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data.size()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_ManagedUser_shouldAddThree() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data.size()).isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_DisallowRemove_shouldAddTwo() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
when(mAccountHelper.hasBaseUserRestriction(eq(UserManager.DISALLOW_REMOVE_USER), anyInt()))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data.size()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateRawDataToIndex_DisallowModify_shouldAddTwo() {
|
||||||
|
final List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
|
final List<UserInfo> infos = new ArrayList<>();
|
||||||
|
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
|
||||||
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
|
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
|
||||||
|
when(mAccountHelper.hasBaseUserRestriction(
|
||||||
|
eq(UserManager.DISALLOW_MODIFY_ACCOUNTS), anyInt())).thenReturn(true);
|
||||||
|
|
||||||
|
mController.updateRawDataToIndex(data);
|
||||||
|
|
||||||
|
assertThat(data.size()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.testutils.shadow;
|
||||||
|
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.AuthenticatorDescription;
|
||||||
|
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
|
@Implements(AccountManager.class)
|
||||||
|
public class ShadowAccountManager {
|
||||||
|
@Implementation
|
||||||
|
public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.testutils.shadow;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.SyncAdapterType;
|
||||||
|
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
|
@Implements(ContentResolver.class)
|
||||||
|
public class ShadowContentResolver {
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
|
||||||
|
return new SyncAdapterType[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user