blob: db3a8eb9e289accb8d615571bd532bbc061f2114 [file] [log] [blame]
Doris Lingbfac31b2016-11-10 15:12:52 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.accounts;
18
Tony Mantler1c9e2f62017-06-13 15:16:50 -070019import static android.content.Intent.EXTRA_USER;
20import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
21import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
22import static android.provider.Settings.ACTION_ADD_ACCOUNT;
23import static android.provider.Settings.EXTRA_AUTHORITIES;
24
Doris Lingbfac31b2016-11-10 15:12:52 -080025import android.accounts.Account;
26import android.accounts.AccountManager;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.pm.ApplicationInfo;
32import android.content.pm.PackageManager;
33import android.content.pm.UserInfo;
34import android.content.res.Resources;
Doris Ling20d4b042016-11-22 16:37:06 -080035import android.graphics.drawable.Drawable;
Doris Lingbfac31b2016-11-10 15:12:52 -080036import android.os.Bundle;
37import android.os.UserHandle;
38import android.os.UserManager;
Fan Zhangfa9849e2018-04-18 15:58:50 -070039import android.text.BidiFormatter;
Doris Ling633250b2017-05-02 11:28:14 -070040import android.util.ArrayMap;
Doris Lingbfac31b2016-11-10 15:12:52 -080041import android.util.Log;
42import android.util.SparseArray;
43
Fan Zhang23f8d592018-08-28 15:11:40 -070044import androidx.annotation.VisibleForTesting;
45import androidx.preference.Preference;
46import androidx.preference.Preference.OnPreferenceClickListener;
47import androidx.preference.PreferenceGroup;
48import androidx.preference.PreferenceScreen;
49
Doris Lingbfac31b2016-11-10 15:12:52 -080050import com.android.settings.AccessiblePreferenceCategory;
Doris Lingbfac31b2016-11-10 15:12:52 -080051import com.android.settings.R;
Doris Lingf074f0f2017-02-24 15:20:05 -080052import com.android.settings.SettingsPreferenceFragment;
Doris Lingbfac31b2016-11-10 15:12:52 -080053import com.android.settings.Utils;
Tony Mantler1d583e12017-06-13 13:09:25 -070054import com.android.settings.core.PreferenceControllerMixin;
Fan Zhang7cf99f52018-02-16 10:37:37 -080055import com.android.settings.core.SubSettingLauncher;
Raff Tsai65866292019-10-05 09:32:19 +080056import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
Doris Lingbfac31b2016-11-10 15:12:52 -080057import com.android.settings.overlay.FeatureFactory;
Doris Lingbfac31b2016-11-10 15:12:52 -080058import com.android.settingslib.RestrictedPreference;
59import com.android.settingslib.accounts.AuthenticatorHelper;
Tony Mantler1d583e12017-06-13 13:09:25 -070060import com.android.settingslib.core.AbstractPreferenceController;
Leif Hendrik Wilden28dee1f2018-01-11 10:15:36 -080061import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
Juan Lang777ed252017-05-09 15:42:36 -070062import com.android.settingslib.core.lifecycle.LifecycleObserver;
63import com.android.settingslib.core.lifecycle.events.OnPause;
64import com.android.settingslib.core.lifecycle.events.OnResume;
Raff Tsai65866292019-10-05 09:32:19 +080065import com.android.settingslib.search.SearchIndexableRaw;
Doris Lingbfac31b2016-11-10 15:12:52 -080066
67import java.util.ArrayList;
68import java.util.Collections;
69import java.util.Comparator;
70import java.util.List;
71
Tony Mantler1d583e12017-06-13 13:09:25 -070072public class AccountPreferenceController extends AbstractPreferenceController
73 implements PreferenceControllerMixin, AuthenticatorHelper.OnAccountsUpdateListener,
Doris Lingbfac31b2016-11-10 15:12:52 -080074 OnPreferenceClickListener, LifecycleObserver, OnPause, OnResume {
75
76 private static final String TAG = "AccountPrefController";
Doris Lingbfac31b2016-11-10 15:12:52 -080077
78 private static final int ORDER_ACCOUNT_PROFILES = 1;
79 private static final int ORDER_LAST = 1002;
80 private static final int ORDER_NEXT_TO_LAST = 1001;
81 private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000;
82
Stanley Wang8015cba2019-11-27 10:39:59 +080083 private static final String PREF_KEY_REMOVE_PROFILE = "remove_profile";
84 private static final String PREF_KEY_WORK_PROFILE_SETTING = "work_profile_setting";
85
Doris Lingbfac31b2016-11-10 15:12:52 -080086 private UserManager mUm;
87 private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
Raff Tsai65866292019-10-05 09:32:19 +080088 private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver =
89 new ManagedProfileBroadcastReceiver();
Doris Lingbfac31b2016-11-10 15:12:52 -080090 private Preference mProfileNotAvailablePreference;
91 private String[] mAuthorities;
92 private int mAuthoritiesCount = 0;
Raff Tsai5c075ba2019-12-16 12:30:05 +080093 private SettingsPreferenceFragment mFragment;
Doris Lingbfac31b2016-11-10 15:12:52 -080094 private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
95 private AccountRestrictionHelper mHelper;
Fan Zhangc6ca3142017-02-14 15:02:35 -080096 private MetricsFeatureProvider mMetricsFeatureProvider;
Raff Tsai65866292019-10-05 09:32:19 +080097 private @ProfileSelectFragment.ProfileType int mType;
Doris Lingbfac31b2016-11-10 15:12:52 -080098
99 /**
100 * Holds data related to the accounts belonging to one profile.
101 */
102 public static class ProfileData {
103 /**
104 * The preference that displays the accounts.
105 */
106 public PreferenceGroup preferenceGroup;
107 /**
108 * The preference that displays the add account button.
109 */
Fan Zhang12b03b22017-10-29 13:57:29 -0700110 public RestrictedPreference addAccountPreference;
Doris Lingbfac31b2016-11-10 15:12:52 -0800111 /**
112 * The preference that displays the button to remove the managed profile
113 */
114 public RestrictedPreference removeWorkProfilePreference;
115 /**
116 * The preference that displays managed profile settings.
117 */
118 public Preference managedProfilePreference;
119 /**
120 * The {@link AuthenticatorHelper} that holds accounts data for this profile.
121 */
122 public AuthenticatorHelper authenticatorHelper;
123 /**
124 * The {@link UserInfo} of the profile.
125 */
126 public UserInfo userInfo;
Doris Ling633250b2017-05-02 11:28:14 -0700127 /**
128 * The {@link UserInfo} of the profile.
129 */
130 public boolean pendingRemoval;
131 /**
Fan Zhangc754f592017-05-17 12:32:59 -0700132 * The map from account key to account preference
Doris Ling633250b2017-05-02 11:28:14 -0700133 */
Fan Zhangc754f592017-05-17 12:32:59 -0700134 public ArrayMap<String, AccountTypePreference> accountPreferences = new ArrayMap<>();
Doris Lingbfac31b2016-11-10 15:12:52 -0800135 }
136
Doris Lingf074f0f2017-02-24 15:20:05 -0800137 public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
Raff Tsai65866292019-10-05 09:32:19 +0800138 String[] authorities, @ProfileSelectFragment.ProfileType int type) {
139 this(context, parent, authorities, new AccountRestrictionHelper(context), type);
Doris Lingbfac31b2016-11-10 15:12:52 -0800140 }
141
142 @VisibleForTesting
Doris Lingf074f0f2017-02-24 15:20:05 -0800143 AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
Raff Tsai65866292019-10-05 09:32:19 +0800144 String[] authorities, AccountRestrictionHelper helper,
145 @ProfileSelectFragment.ProfileType int type) {
Doris Lingbfac31b2016-11-10 15:12:52 -0800146 super(context);
147 mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
148 mAuthorities = authorities;
Raff Tsai5c075ba2019-12-16 12:30:05 +0800149 mFragment = parent;
Doris Lingbfac31b2016-11-10 15:12:52 -0800150 if (mAuthorities != null) {
151 mAuthoritiesCount = mAuthorities.length;
152 }
Fan Zhangc6ca3142017-02-14 15:02:35 -0800153 final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
Fan Zhangc6ca3142017-02-14 15:02:35 -0800154 mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
Doris Lingbfac31b2016-11-10 15:12:52 -0800155 mHelper = helper;
Raff Tsai65866292019-10-05 09:32:19 +0800156 mType = type;
Doris Lingbfac31b2016-11-10 15:12:52 -0800157 }
158
159 @Override
160 public boolean isAvailable() {
161 return !mUm.isManagedProfile();
162 }
163
164 @Override
Doris Lingbfac31b2016-11-10 15:12:52 -0800165 public String getPreferenceKey() {
166 return null;
167 }
168
169 @Override
Doris Ling633250b2017-05-02 11:28:14 -0700170 public void displayPreference(PreferenceScreen screen) {
171 super.displayPreference(screen);
172 updateUi();
173 }
174
175 @Override
Stanley Wang8015cba2019-11-27 10:39:59 +0800176 public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
Doris Lingbfac31b2016-11-10 15:12:52 -0800177 if (!isAvailable()) {
178 return;
179 }
180 final Resources res = mContext.getResources();
181 final String screenTitle = res.getString(R.string.account_settings_title);
182
183 List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
Stanley Wang8015cba2019-11-27 10:39:59 +0800184 for (final UserInfo userInfo : profiles) {
185 if (userInfo.isEnabled() && userInfo.isManagedProfile()) {
186 if (!mHelper.hasBaseUserRestriction(DISALLOW_REMOVE_MANAGED_PROFILE,
187 UserHandle.myUserId())) {
188 final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
189 data.key = PREF_KEY_REMOVE_PROFILE;
190 data.title = res.getString(R.string.remove_managed_profile_label);
Doris Lingbfac31b2016-11-10 15:12:52 -0800191 data.screenTitle = screenTitle;
192 rawData.add(data);
193 }
Stanley Wang8015cba2019-11-27 10:39:59 +0800194 final SearchIndexableRaw data = new SearchIndexableRaw(mContext);
195 data.key = PREF_KEY_WORK_PROFILE_SETTING;
196 data.title = res.getString(R.string.managed_profile_settings_title);
197 data.screenTitle = screenTitle;
198 rawData.add(data);
Doris Lingbfac31b2016-11-10 15:12:52 -0800199 }
200 }
201 }
202
203 @Override
204 public void onResume() {
Doris Lingbfac31b2016-11-10 15:12:52 -0800205 updateUi();
206 mManagedProfileBroadcastReceiver.register(mContext);
207 listenToAccountUpdates();
208 }
209
210 @Override
211 public void onPause() {
212 stopListeningToAccountUpdates();
213 mManagedProfileBroadcastReceiver.unregister(mContext);
214 }
215
216 @Override
217 public void onAccountsUpdate(UserHandle userHandle) {
218 final ProfileData profileData = mProfiles.get(userHandle.getIdentifier());
219 if (profileData != null) {
220 updateAccountTypes(profileData);
221 } else {
222 Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier());
223 }
224 }
225
226 @Override
227 public boolean onPreferenceClick(Preference preference) {
228 // Check the preference
229 final int count = mProfiles.size();
230 for (int i = 0; i < count; i++) {
231 ProfileData profileData = mProfiles.valueAt(i);
232 if (preference == profileData.addAccountPreference) {
Tony Mantler1c9e2f62017-06-13 15:16:50 -0700233 Intent intent = new Intent(ACTION_ADD_ACCOUNT);
Doris Lingbfac31b2016-11-10 15:12:52 -0800234 intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle());
235 intent.putExtra(EXTRA_AUTHORITIES, mAuthorities);
236 mContext.startActivity(intent);
237 return true;
238 }
239 if (preference == profileData.removeWorkProfilePreference) {
240 final int userId = profileData.userInfo.id;
Raff Tsai5c075ba2019-12-16 12:30:05 +0800241 RemoveUserFragment.newInstance(userId).show(mFragment.getFragmentManager(),
Doris Lingbfac31b2016-11-10 15:12:52 -0800242 "removeUser");
243 return true;
244 }
245 if (preference == profileData.managedProfilePreference) {
246 Bundle arguments = new Bundle();
247 arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle());
Fan Zhang7cf99f52018-02-16 10:37:37 -0800248 new SubSettingLauncher(mContext)
Raff Tsai5c075ba2019-12-16 12:30:05 +0800249 .setSourceMetricsCategory(mFragment.getMetricsCategory())
Fan Zhang7cf99f52018-02-16 10:37:37 -0800250 .setDestination(ManagedProfileSettings.class.getName())
hjchangliaoe86eec02018-05-02 13:01:07 +0800251 .setTitleRes(R.string.managed_profile_settings_title)
Fan Zhang7cf99f52018-02-16 10:37:37 -0800252 .setArguments(arguments)
253 .launch();
254
Doris Lingbfac31b2016-11-10 15:12:52 -0800255 return true;
256 }
257 }
258 return false;
259 }
260
Doris Lingbfac31b2016-11-10 15:12:52 -0800261 private void updateUi() {
Doris Lingbfac31b2016-11-10 15:12:52 -0800262 if (!isAvailable()) {
263 // This should not happen
264 Log.e(TAG, "We should not be showing settings for a managed profile");
Doris Lingbfac31b2016-11-10 15:12:52 -0800265 return;
266 }
267
Doris Ling633250b2017-05-02 11:28:14 -0700268 for (int i = 0, size = mProfiles.size(); i < size; i++) {
269 mProfiles.valueAt(i).pendingRemoval = true;
270 }
James Lemieux22a39c22018-02-26 00:51:42 -0800271 if (mUm.isRestrictedProfile()) {
Doris Lingbfac31b2016-11-10 15:12:52 -0800272 // Restricted user or similar
273 UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
274 updateProfileUi(userInfo);
275 } else {
276 List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
277 final int profilesCount = profiles.size();
Doris Lingbfac31b2016-11-10 15:12:52 -0800278 for (int i = 0; i < profilesCount; i++) {
Raff Tsai65866292019-10-05 09:32:19 +0800279 if (profiles.get(i).isManagedProfile()
Raff Tsai1e5d8142019-12-12 11:45:41 +0800280 && (mType & ProfileSelectFragment.ProfileType.WORK) != 0) {
Raff Tsai65866292019-10-05 09:32:19 +0800281 updateProfileUi(profiles.get(i));
282 } else if (!profiles.get(i).isManagedProfile()
Raff Tsai1e5d8142019-12-12 11:45:41 +0800283 && (mType & ProfileSelectFragment.ProfileType.PERSONAL) != 0) {
Raff Tsai65866292019-10-05 09:32:19 +0800284 updateProfileUi(profiles.get(i));
285 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800286 }
287 }
Doris Ling633250b2017-05-02 11:28:14 -0700288 cleanUpPreferences();
Doris Lingbfac31b2016-11-10 15:12:52 -0800289
290 // Add all preferences, starting with one for the primary profile.
291 // Note that we're relying on the ordering given by the SparseArray keys, and on the
292 // value of UserHandle.USER_OWNER being smaller than all the rest.
293 final int profilesCount = mProfiles.size();
294 for (int i = 0; i < profilesCount; i++) {
295 updateAccountTypes(mProfiles.valueAt(i));
296 }
297 }
298
299 private void updateProfileUi(final UserInfo userInfo) {
Raff Tsai5c075ba2019-12-16 12:30:05 +0800300 if (mFragment.getPreferenceManager() == null) {
Fan Zhang81a030f2017-01-11 10:46:45 -0800301 return;
302 }
Doris Ling633250b2017-05-02 11:28:14 -0700303 final ProfileData data = mProfiles.get(userInfo.id);
304 if (data != null) {
305 data.pendingRemoval = false;
Doris Lingce5f9c02018-07-23 16:13:39 -0700306 data.userInfo = userInfo;
Doris Ling71090672017-05-16 17:23:55 -0700307 if (userInfo.isEnabled()) {
308 // recreate the authentication helper to refresh the list of enabled accounts
309 data.authenticatorHelper =
Raff Tsai65866292019-10-05 09:32:19 +0800310 new AuthenticatorHelper(mContext, userInfo.getUserHandle(), this);
Doris Ling71090672017-05-16 17:23:55 -0700311 }
Doris Ling633250b2017-05-02 11:28:14 -0700312 return;
313 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800314 final Context context = mContext;
315 final ProfileData profileData = new ProfileData();
316 profileData.userInfo = userInfo;
317 AccessiblePreferenceCategory preferenceGroup =
Raff Tsai65866292019-10-05 09:32:19 +0800318 mHelper.createAccessiblePreferenceCategory(
Raff Tsai5c075ba2019-12-16 12:30:05 +0800319 mFragment.getPreferenceManager().getContext());
Doris Lingbfac31b2016-11-10 15:12:52 -0800320 preferenceGroup.setOrder(mAccountProfileOrder++);
321 if (isSingleProfile()) {
Doris Ling829d3aa2017-02-03 15:06:56 -0800322 preferenceGroup.setTitle(context.getString(R.string.account_for_section_header,
Fan Zhangfa9849e2018-04-18 15:58:50 -0700323 BidiFormatter.getInstance().unicodeWrap(userInfo.name)));
Doris Lingbfac31b2016-11-10 15:12:52 -0800324 preferenceGroup.setContentDescription(
Raff Tsai65866292019-10-05 09:32:19 +0800325 mContext.getString(R.string.account_settings));
Doris Lingbfac31b2016-11-10 15:12:52 -0800326 } else if (userInfo.isManagedProfile()) {
Raff Tsai1e5d8142019-12-12 11:45:41 +0800327 if (mType == ProfileSelectFragment.ProfileType.ALL) {
Raff Tsaif5277ba2019-11-07 14:53:54 +0800328 preferenceGroup.setTitle(R.string.category_work);
329 final String workGroupSummary = getWorkGroupSummary(context, userInfo);
330 preferenceGroup.setSummary(workGroupSummary);
331 preferenceGroup.setContentDescription(
332 mContext.getString(R.string.accessibility_category_work, workGroupSummary));
333 }
Fan Zhang12b03b22017-10-29 13:57:29 -0700334 profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference();
Doris Lingbfac31b2016-11-10 15:12:52 -0800335 mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
Raff Tsai65866292019-10-05 09:32:19 +0800336 DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
Doris Lingbfac31b2016-11-10 15:12:52 -0800337 profileData.managedProfilePreference = newManagedProfileSettings();
338 } else {
Raff Tsai1e5d8142019-12-12 11:45:41 +0800339 if (mType == ProfileSelectFragment.ProfileType.ALL) {
Raff Tsaif5277ba2019-11-07 14:53:54 +0800340 preferenceGroup.setTitle(R.string.category_personal);
341 preferenceGroup.setContentDescription(
342 mContext.getString(R.string.accessibility_category_personal));
343 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800344 }
Raff Tsai5c075ba2019-12-16 12:30:05 +0800345 final PreferenceScreen screen = mFragment.getPreferenceScreen();
Fan Zhang424443b2017-01-10 11:50:01 -0800346 if (screen != null) {
347 screen.addPreference(preferenceGroup);
348 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800349 profileData.preferenceGroup = preferenceGroup;
350 if (userInfo.isEnabled()) {
351 profileData.authenticatorHelper = new AuthenticatorHelper(context,
352 userInfo.getUserHandle(), this);
Fan Zhang12b03b22017-10-29 13:57:29 -0700353 profileData.addAccountPreference = newAddAccountPreference();
Doris Lingbfac31b2016-11-10 15:12:52 -0800354 mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
Raff Tsai65866292019-10-05 09:32:19 +0800355 DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
Doris Lingbfac31b2016-11-10 15:12:52 -0800356 }
357 mProfiles.put(userInfo.id, profileData);
Doris Lingbfac31b2016-11-10 15:12:52 -0800358 }
359
Fan Zhang12b03b22017-10-29 13:57:29 -0700360 private RestrictedPreference newAddAccountPreference() {
361 RestrictedPreference preference =
Raff Tsai5c075ba2019-12-16 12:30:05 +0800362 new RestrictedPreference(mFragment.getPreferenceManager().getContext());
Doris Lingbfac31b2016-11-10 15:12:52 -0800363 preference.setTitle(R.string.add_account_label);
Amin Shaikh3f1de202019-05-01 17:29:02 -0400364 preference.setIcon(R.drawable.ic_add_24dp);
Doris Lingbfac31b2016-11-10 15:12:52 -0800365 preference.setOnPreferenceClickListener(this);
366 preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST);
367 return preference;
368 }
369
Fan Zhang12b03b22017-10-29 13:57:29 -0700370 private RestrictedPreference newRemoveWorkProfilePreference() {
Doris Lingbfac31b2016-11-10 15:12:52 -0800371 RestrictedPreference preference = new RestrictedPreference(
Raff Tsai5c075ba2019-12-16 12:30:05 +0800372 mFragment.getPreferenceManager().getContext());
Stanley Wang8015cba2019-11-27 10:39:59 +0800373 preference.setKey(PREF_KEY_REMOVE_PROFILE);
Doris Lingbfac31b2016-11-10 15:12:52 -0800374 preference.setTitle(R.string.remove_managed_profile_label);
Antony Sargent0d9afde2018-05-17 11:55:40 -0700375 preference.setIcon(R.drawable.ic_delete);
Doris Lingbfac31b2016-11-10 15:12:52 -0800376 preference.setOnPreferenceClickListener(this);
377 preference.setOrder(ORDER_LAST);
378 return preference;
379 }
380
381
382 private Preference newManagedProfileSettings() {
Raff Tsai5c075ba2019-12-16 12:30:05 +0800383 Preference preference = new Preference(mFragment.getPreferenceManager().getContext());
Stanley Wang8015cba2019-11-27 10:39:59 +0800384 preference.setKey(PREF_KEY_WORK_PROFILE_SETTING);
Doris Lingbfac31b2016-11-10 15:12:52 -0800385 preference.setTitle(R.string.managed_profile_settings_title);
Fan Zhang41c4e5f2018-04-03 13:21:34 -0700386 preference.setIcon(R.drawable.ic_settings_24dp);
Doris Lingbfac31b2016-11-10 15:12:52 -0800387 preference.setOnPreferenceClickListener(this);
388 preference.setOrder(ORDER_NEXT_TO_LAST);
389 return preference;
390 }
391
392 private String getWorkGroupSummary(Context context, UserInfo userInfo) {
393 PackageManager packageManager = context.getPackageManager();
394 ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id);
395 if (adminApplicationInfo == null) {
396 return null;
397 }
398 CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo);
399 return mContext.getString(R.string.managing_admin, appLabel);
400 }
401
402 void cleanUpPreferences() {
Raff Tsai5c075ba2019-12-16 12:30:05 +0800403 PreferenceScreen screen = mFragment.getPreferenceScreen();
Fan Zhang424443b2017-01-10 11:50:01 -0800404 if (screen == null) {
405 return;
406 }
Doris Ling633250b2017-05-02 11:28:14 -0700407 final int count = mProfiles.size();
Raff Tsai65866292019-10-05 09:32:19 +0800408 for (int i = count - 1; i >= 0; i--) {
Doris Ling633250b2017-05-02 11:28:14 -0700409 final ProfileData data = mProfiles.valueAt(i);
410 if (data.pendingRemoval) {
411 screen.removePreference(data.preferenceGroup);
412 mProfiles.removeAt(i);
413 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800414 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800415 }
416
417 private void listenToAccountUpdates() {
418 final int count = mProfiles.size();
419 for (int i = 0; i < count; i++) {
420 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
421 if (authenticatorHelper != null) {
422 authenticatorHelper.listenToAccountUpdates();
423 }
424 }
425 }
426
427 private void stopListeningToAccountUpdates() {
428 final int count = mProfiles.size();
429 for (int i = 0; i < count; i++) {
430 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper;
431 if (authenticatorHelper != null) {
432 authenticatorHelper.stopListeningToAccountUpdates();
433 }
434 }
435 }
436
437 private void updateAccountTypes(ProfileData profileData) {
Raff Tsai5c075ba2019-12-16 12:30:05 +0800438 if (mFragment.getPreferenceManager() == null
Fan Zhangc7804c12017-01-13 14:57:01 -0800439 || profileData.preferenceGroup.getPreferenceManager() == null) {
Fan Zhang81a030f2017-01-11 10:46:45 -0800440 // This could happen if activity is finishing
441 return;
442 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800443 if (profileData.userInfo.isEnabled()) {
Fan Zhangc754f592017-05-17 12:32:59 -0700444 final ArrayMap<String, AccountTypePreference> preferenceToRemove =
Doris Ling633250b2017-05-02 11:28:14 -0700445 new ArrayMap<>(profileData.accountPreferences);
Doris Ling20d4b042016-11-22 16:37:06 -0800446 final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
Doris Ling633250b2017-05-02 11:28:14 -0700447 profileData.authenticatorHelper, profileData.userInfo.getUserHandle(),
448 preferenceToRemove);
Doris Lingbfac31b2016-11-10 15:12:52 -0800449 final int count = preferences.size();
450 for (int i = 0; i < count; i++) {
Doris Ling633250b2017-05-02 11:28:14 -0700451 final AccountTypePreference preference = preferences.get(i);
452 preference.setOrder(i);
Fan Zhangc754f592017-05-17 12:32:59 -0700453 final String key = preference.getKey();
454 if (!profileData.accountPreferences.containsKey(key)) {
455 profileData.preferenceGroup.addPreference(preference);
456 profileData.accountPreferences.put(key, preference);
Doris Ling633250b2017-05-02 11:28:14 -0700457 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800458 }
459 if (profileData.addAccountPreference != null) {
460 profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
461 }
Fan Zhangc754f592017-05-17 12:32:59 -0700462 for (String key : preferenceToRemove.keySet()) {
Doris Ling633250b2017-05-02 11:28:14 -0700463 profileData.preferenceGroup.removePreference(
Raff Tsai65866292019-10-05 09:32:19 +0800464 profileData.accountPreferences.get(key));
Fan Zhangc754f592017-05-17 12:32:59 -0700465 profileData.accountPreferences.remove(key);
Doris Ling633250b2017-05-02 11:28:14 -0700466 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800467 } else {
Doris Ling633250b2017-05-02 11:28:14 -0700468 profileData.preferenceGroup.removeAll();
Doris Lingbfac31b2016-11-10 15:12:52 -0800469 // Put a label instead of the accounts list
470 if (mProfileNotAvailablePreference == null) {
471 mProfileNotAvailablePreference =
Raff Tsai5c075ba2019-12-16 12:30:05 +0800472 new Preference(mFragment.getPreferenceManager().getContext());
Doris Lingbfac31b2016-11-10 15:12:52 -0800473 }
474 mProfileNotAvailablePreference.setEnabled(false);
475 mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
476 mProfileNotAvailablePreference.setTitle(null);
477 mProfileNotAvailablePreference.setSummary(
478 R.string.managed_profile_not_available_label);
479 profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference);
480 }
481 if (profileData.removeWorkProfilePreference != null) {
482 profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference);
483 }
484 if (profileData.managedProfilePreference != null) {
485 profileData.preferenceGroup.addPreference(profileData.managedProfilePreference);
486 }
487 }
488
Doris Ling20d4b042016-11-22 16:37:06 -0800489 private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
Fan Zhangc754f592017-05-17 12:32:59 -0700490 UserHandle userHandle, ArrayMap<String, AccountTypePreference> preferenceToRemove) {
Doris Lingbfac31b2016-11-10 15:12:52 -0800491 final String[] accountTypes = helper.getEnabledAccountTypes();
Doris Ling20d4b042016-11-22 16:37:06 -0800492 final ArrayList<AccountTypePreference> accountTypePreferences =
Fan Zhangc6ca3142017-02-14 15:02:35 -0800493 new ArrayList<>(accountTypes.length);
Doris Lingbfac31b2016-11-10 15:12:52 -0800494
495 for (int i = 0; i < accountTypes.length; i++) {
496 final String accountType = accountTypes[i];
497 // Skip showing any account that does not have any of the requested authorities
498 if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) {
499 continue;
500 }
501 final CharSequence label = helper.getLabelForType(mContext, accountType);
502 if (label == null) {
503 continue;
504 }
505 final String titleResPackageName = helper.getPackageForType(accountType);
506 final int titleResId = helper.getLabelIdForType(accountType);
507
508 final Account[] accounts = AccountManager.get(mContext)
509 .getAccountsByTypeAsUser(accountType, userHandle);
Doris Ling20d4b042016-11-22 16:37:06 -0800510 final Drawable icon = helper.getDrawableForType(mContext, accountType);
Raff Tsai5c075ba2019-12-16 12:30:05 +0800511 final Context prefContext = mFragment.getPreferenceManager().getContext();
Doris Lingbfac31b2016-11-10 15:12:52 -0800512
Doris Lingf074f0f2017-02-24 15:20:05 -0800513 // Add a preference row for each individual account
514 for (Account account : accounts) {
Fan Zhangc754f592017-05-17 12:32:59 -0700515 final AccountTypePreference preference =
516 preferenceToRemove.remove(AccountTypePreference.buildKey(account));
Doris Ling633250b2017-05-02 11:28:14 -0700517 if (preference != null) {
518 accountTypePreferences.add(preference);
519 continue;
520 }
Doris Lingf074f0f2017-02-24 15:20:05 -0800521 final ArrayList<String> auths =
Raff Tsai65866292019-10-05 09:32:19 +0800522 helper.getAuthoritiesForAccountType(account.type);
Doris Lingf074f0f2017-02-24 15:20:05 -0800523 if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
524 continue;
Doris Ling20d4b042016-11-22 16:37:06 -0800525 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800526 final Bundle fragmentArguments = new Bundle();
Doris Lingf074f0f2017-02-24 15:20:05 -0800527 fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
Raff Tsai65866292019-10-05 09:32:19 +0800528 account);
Doris Lingf074f0f2017-02-24 15:20:05 -0800529 fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
Raff Tsai65866292019-10-05 09:32:19 +0800530 userHandle);
Doris Lingf074f0f2017-02-24 15:20:05 -0800531 fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
Raff Tsai65866292019-10-05 09:32:19 +0800532 accountType);
Doris Lingf074f0f2017-02-24 15:20:05 -0800533 fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
Raff Tsai65866292019-10-05 09:32:19 +0800534 label.toString());
Doris Lingf074f0f2017-02-24 15:20:05 -0800535 fragmentArguments.putInt(AccountDetailDashboardFragment.KEY_ACCOUNT_TITLE_RES,
Raff Tsai65866292019-10-05 09:32:19 +0800536 titleResId);
Doris Lingbfac31b2016-11-10 15:12:52 -0800537 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
Doris Ling20d4b042016-11-22 16:37:06 -0800538 accountTypePreferences.add(new AccountTypePreference(
Raff Tsai5c075ba2019-12-16 12:30:05 +0800539 prefContext, mMetricsFeatureProvider.getMetricsCategory(mFragment),
Raff Tsai65866292019-10-05 09:32:19 +0800540 account, titleResPackageName, titleResId, label,
541 AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
Doris Lingbfac31b2016-11-10 15:12:52 -0800542 }
543 helper.preloadDrawableForType(mContext, accountType);
544 }
545 // Sort by label
Doris Ling20d4b042016-11-22 16:37:06 -0800546 Collections.sort(accountTypePreferences, new Comparator<AccountTypePreference>() {
Doris Lingbfac31b2016-11-10 15:12:52 -0800547 @Override
Doris Ling20d4b042016-11-22 16:37:06 -0800548 public int compare(AccountTypePreference t1, AccountTypePreference t2) {
Doris Lingf074f0f2017-02-24 15:20:05 -0800549 int result = t1.getSummary().toString().compareTo(t2.getSummary().toString());
Doris Ling20d4b042016-11-22 16:37:06 -0800550 return result != 0
Raff Tsai65866292019-10-05 09:32:19 +0800551 ? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
Doris Lingbfac31b2016-11-10 15:12:52 -0800552 }
553 });
554 return accountTypePreferences;
555 }
556
557 private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper,
558 String accountType) {
559 if (mAuthoritiesCount == 0) {
560 // No authorities required
561 return true;
562 }
563 final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType(
564 accountType);
565 if (authoritiesForType == null) {
566 Log.d(TAG, "No sync authorities for account type: " + accountType);
567 return false;
568 }
569 for (int j = 0; j < mAuthoritiesCount; j++) {
570 if (authoritiesForType.contains(mAuthorities[j])) {
571 return true;
572 }
573 }
574 return false;
575 }
576
577 private boolean isSingleProfile() {
578 return mUm.isLinkedUser() || mUm.getProfiles(UserHandle.myUserId()).size() == 1;
579 }
580
581 private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
582 private boolean mListeningToManagedProfileEvents;
583
584 @Override
585 public void onReceive(Context context, Intent intent) {
586 final String action = intent.getAction();
587 Log.v(TAG, "Received broadcast: " + action);
588 if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
589 || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
Raff Tsai5c075ba2019-12-16 12:30:05 +0800590 if (mFragment instanceof AccountWorkProfileDashboardFragment) {
591 mFragment.getActivity().finish();
592 } else {
593 // Clean old state
594 stopListeningToAccountUpdates();
595 // Build new state
596 updateUi();
597 listenToAccountUpdates();
598 }
Doris Lingbfac31b2016-11-10 15:12:52 -0800599 return;
600 }
601 Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
602 }
603
604 public void register(Context context) {
605 if (!mListeningToManagedProfileEvents) {
606 IntentFilter intentFilter = new IntentFilter();
607 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
608 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
609 context.registerReceiver(this, intentFilter);
610 mListeningToManagedProfileEvents = true;
611 }
612 }
613
614 public void unregister(Context context) {
615 if (mListeningToManagedProfileEvents) {
616 context.unregisterReceiver(this);
617 mListeningToManagedProfileEvents = false;
618 }
619 }
620 }
621}