1 /* 2 * Copyright (C) 2014 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 17 package com.android.settings.accounts; 18 19 20 import android.accounts.Account; 21 import android.accounts.AccountManager; 22 import android.app.ActivityManager; 23 import android.app.AlertDialog; 24 import android.app.Dialog; 25 import android.app.DialogFragment; 26 import android.content.BroadcastReceiver; 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.DialogInterface; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.UserInfo; 35 import android.content.res.Resources; 36 import android.graphics.drawable.Drawable; 37 import android.os.Bundle; 38 import android.os.Process; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.provider.SearchIndexableResource; 42 import android.support.v7.preference.Preference; 43 import android.support.v7.preference.Preference.OnPreferenceClickListener; 44 import android.support.v7.preference.PreferenceGroup; 45 import android.support.v7.preference.PreferenceScreen; 46 import android.util.Log; 47 import android.util.SparseArray; 48 import android.view.Menu; 49 import android.view.MenuInflater; 50 import android.view.MenuItem; 51 52 import com.android.internal.logging.MetricsProto.MetricsEvent; 53 import com.android.settings.AccessiblePreferenceCategory; 54 import com.android.settings.DimmableIconPreference; 55 import com.android.settings.R; 56 import com.android.settings.SettingsActivity; 57 import com.android.settings.SettingsPreferenceFragment; 58 import com.android.settings.Utils; 59 import com.android.settings.search.BaseSearchIndexProvider; 60 import com.android.settings.search.Index; 61 import com.android.settings.search.Indexable; 62 import com.android.settings.search.SearchIndexableRaw; 63 import com.android.settings.users.UserDialogs; 64 import com.android.settingslib.RestrictedLockUtils; 65 import com.android.settingslib.accounts.AuthenticatorHelper; 66 67 import java.util.ArrayList; 68 import java.util.Arrays; 69 import java.util.Collections; 70 import java.util.Comparator; 71 import java.util.List; 72 73 import static android.content.Intent.EXTRA_USER; 74 import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS; 75 import static android.provider.Settings.EXTRA_AUTHORITIES; 76 77 /** 78 * Settings screen for the account types on the device. 79 * This shows all account types available for personal and work profiles. 80 * 81 * An extra {@link UserHandle} can be specified in the intent as {@link EXTRA_USER}, if the user for 82 * which the action needs to be performed is different to the one the Settings App will run in. 83 */ 84 public class AccountSettings extends SettingsPreferenceFragment 85 implements AuthenticatorHelper.OnAccountsUpdateListener, 86 OnPreferenceClickListener, Indexable { 87 public static final String TAG = "AccountSettings"; 88 89 private static final String KEY_ACCOUNT = "account"; 90 91 private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS"; 92 private static final String TAG_CONFIRM_AUTO_SYNC_CHANGE = "confirmAutoSyncChange"; 93 94 private static final int ORDER_LAST = 1002; 95 private static final int ORDER_NEXT_TO_LAST = 1001; 96 private static final int ORDER_NEXT_TO_NEXT_TO_LAST = 1000; 97 98 private UserManager mUm; 99 private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>(); 100 private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver 101 = new ManagedProfileBroadcastReceiver(); 102 private Preference mProfileNotAvailablePreference; 103 private String[] mAuthorities; 104 private int mAuthoritiesCount = 0; 105 106 /** 107 * Holds data related to the accounts belonging to one profile. 108 */ 109 private static class ProfileData { 110 /** 111 * The preference that displays the accounts. 112 */ 113 public PreferenceGroup preferenceGroup; 114 /** 115 * The preference that displays the add account button. 116 */ 117 public DimmableIconPreference addAccountPreference; 118 /** 119 * The preference that displays the button to remove the managed profile 120 */ 121 public Preference removeWorkProfilePreference; 122 /** 123 * The preference that displays managed profile settings. 124 */ 125 public Preference managedProfilePreference; 126 /** 127 * The {@link AuthenticatorHelper} that holds accounts data for this profile. 128 */ 129 public AuthenticatorHelper authenticatorHelper; 130 /** 131 * The {@link UserInfo} of the profile. 132 */ 133 public UserInfo userInfo; 134 } 135 136 @Override getMetricsCategory()137 protected int getMetricsCategory() { 138 return MetricsEvent.ACCOUNT; 139 } 140 141 @Override onCreate(Bundle savedInstanceState)142 public void onCreate(Bundle savedInstanceState) { 143 super.onCreate(savedInstanceState); 144 mUm = (UserManager) getSystemService(Context.USER_SERVICE); 145 mProfileNotAvailablePreference = new Preference(getPrefContext()); 146 mAuthorities = getActivity().getIntent().getStringArrayExtra(EXTRA_AUTHORITIES); 147 if (mAuthorities != null) { 148 mAuthoritiesCount = mAuthorities.length; 149 } 150 setHasOptionsMenu(true); 151 } 152 153 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)154 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 155 inflater.inflate(R.menu.account_settings, menu); 156 super.onCreateOptionsMenu(menu, inflater); 157 } 158 159 @Override onPrepareOptionsMenu(Menu menu)160 public void onPrepareOptionsMenu(Menu menu) { 161 final UserHandle currentProfile = Process.myUserHandle(); 162 if (mProfiles.size() == 1) { 163 menu.findItem(R.id.account_settings_menu_auto_sync) 164 .setVisible(true) 165 .setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile)) 166 .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser( 167 currentProfile.getIdentifier())); 168 menu.findItem(R.id.account_settings_menu_auto_sync_personal).setVisible(false); 169 menu.findItem(R.id.account_settings_menu_auto_sync_work).setVisible(false); 170 } else if (mProfiles.size() > 1) { 171 // We assume there's only one managed profile, otherwise UI needs to change 172 final UserHandle managedProfile = mProfiles.valueAt(1).userInfo.getUserHandle(); 173 174 menu.findItem(R.id.account_settings_menu_auto_sync_personal) 175 .setVisible(true) 176 .setOnMenuItemClickListener(new MasterSyncStateClickListener(currentProfile)) 177 .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser( 178 currentProfile.getIdentifier())); 179 menu.findItem(R.id.account_settings_menu_auto_sync_work) 180 .setVisible(true) 181 .setOnMenuItemClickListener(new MasterSyncStateClickListener(managedProfile)) 182 .setChecked(ContentResolver.getMasterSyncAutomaticallyAsUser( 183 managedProfile.getIdentifier())); 184 menu.findItem(R.id.account_settings_menu_auto_sync).setVisible(false); 185 } else { 186 Log.w(TAG, "Method onPrepareOptionsMenu called before mProfiles was initialized"); 187 } 188 } 189 190 @Override onResume()191 public void onResume() { 192 super.onResume(); 193 cleanUpPreferences(); 194 updateUi(); 195 mManagedProfileBroadcastReceiver.register(getActivity()); 196 listenToAccountUpdates(); 197 } 198 199 @Override onPause()200 public void onPause() { 201 super.onPause(); 202 stopListeningToAccountUpdates(); 203 mManagedProfileBroadcastReceiver.unregister(getActivity()); 204 } 205 206 @Override onAccountsUpdate(UserHandle userHandle)207 public void onAccountsUpdate(UserHandle userHandle) { 208 final ProfileData profileData = mProfiles.get(userHandle.getIdentifier()); 209 if (profileData != null) { 210 updateAccountTypes(profileData); 211 } else { 212 Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier()); 213 } 214 } 215 216 @Override onPreferenceClick(Preference preference)217 public boolean onPreferenceClick(Preference preference) { 218 // Check the preference 219 final int count = mProfiles.size(); 220 for (int i = 0; i < count; i++) { 221 ProfileData profileData = mProfiles.valueAt(i); 222 if (preference == profileData.addAccountPreference) { 223 Intent intent = new Intent(ADD_ACCOUNT_ACTION); 224 intent.putExtra(EXTRA_USER, profileData.userInfo.getUserHandle()); 225 intent.putExtra(EXTRA_AUTHORITIES, mAuthorities); 226 startActivity(intent); 227 return true; 228 } 229 if (preference == profileData.removeWorkProfilePreference) { 230 final int userId = profileData.userInfo.id; 231 UserDialogs.createRemoveDialog(getActivity(), userId, 232 new DialogInterface.OnClickListener() { 233 @Override 234 public void onClick(DialogInterface dialog, int which) { 235 mUm.removeUser(userId); 236 } 237 } 238 ).show(); 239 return true; 240 } 241 if (preference == profileData.managedProfilePreference) { 242 Bundle arguments = new Bundle(); 243 arguments.putParcelable(Intent.EXTRA_USER, profileData.userInfo.getUserHandle()); 244 ((SettingsActivity) getActivity()).startPreferencePanel( 245 ManagedProfileSettings.class.getName(), arguments, 246 R.string.managed_profile_settings_title, null, null, 0); 247 return true; 248 } 249 } 250 return false; 251 } 252 updateUi()253 void updateUi() { 254 // Load the preferences from an XML resource 255 addPreferencesFromResource(R.xml.account_settings); 256 257 if (Utils.isManagedProfile(mUm)) { 258 // This should not happen 259 Log.e(TAG, "We should not be showing settings for a managed profile"); 260 finish(); 261 return; 262 } 263 264 final PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference(KEY_ACCOUNT); 265 if(mUm.isLinkedUser()) { 266 // Restricted user or similar 267 UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId()); 268 updateProfileUi(userInfo, false /* no category needed */, preferenceScreen); 269 } else { 270 List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId()); 271 final int profilesCount = profiles.size(); 272 final boolean addCategory = profilesCount > 1; 273 for (int i = 0; i < profilesCount; i++) { 274 updateProfileUi(profiles.get(i), addCategory, preferenceScreen); 275 } 276 } 277 278 // Add all preferences, starting with one for the primary profile. 279 // Note that we're relying on the ordering given by the SparseArray keys, and on the 280 // value of UserHandle.USER_OWNER being smaller than all the rest. 281 final int profilesCount = mProfiles.size(); 282 for (int i = 0; i < profilesCount; i++) { 283 ProfileData profileData = mProfiles.valueAt(i); 284 if (!profileData.preferenceGroup.equals(preferenceScreen)) { 285 preferenceScreen.addPreference(profileData.preferenceGroup); 286 } 287 updateAccountTypes(profileData); 288 } 289 } 290 updateProfileUi(final UserInfo userInfo, boolean addCategory, PreferenceScreen parent)291 private void updateProfileUi(final UserInfo userInfo, boolean addCategory, 292 PreferenceScreen parent) { 293 final Context context = getActivity(); 294 final ProfileData profileData = new ProfileData(); 295 profileData.userInfo = userInfo; 296 if (addCategory) { 297 profileData.preferenceGroup = new AccessiblePreferenceCategory(getPrefContext()); 298 if (userInfo.isManagedProfile()) { 299 profileData.preferenceGroup.setLayoutResource(R.layout.work_profile_category); 300 profileData.preferenceGroup.setTitle(R.string.category_work); 301 String workGroupSummary = getWorkGroupSummary(context, userInfo); 302 profileData.preferenceGroup.setSummary(workGroupSummary); 303 ((AccessiblePreferenceCategory) profileData.preferenceGroup).setContentDescription( 304 getString(R.string.accessibility_category_work, workGroupSummary)); 305 profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference(context); 306 profileData.managedProfilePreference = newManagedProfileSettings(); 307 } else { 308 profileData.preferenceGroup.setTitle(R.string.category_personal); 309 ((AccessiblePreferenceCategory) profileData.preferenceGroup).setContentDescription( 310 getString(R.string.accessibility_category_personal)); 311 } 312 parent.addPreference(profileData.preferenceGroup); 313 } else { 314 profileData.preferenceGroup = parent; 315 } 316 if (userInfo.isEnabled()) { 317 profileData.authenticatorHelper = new AuthenticatorHelper(context, 318 userInfo.getUserHandle(), this); 319 if (!RestrictedLockUtils.hasBaseUserRestriction(context, 320 UserManager.DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) { 321 profileData.addAccountPreference = newAddAccountPreference(context); 322 profileData.addAccountPreference.checkRestrictionAndSetDisabled( 323 DISALLOW_MODIFY_ACCOUNTS, userInfo.id); 324 } 325 } 326 mProfiles.put(userInfo.id, profileData); 327 Index.getInstance(getActivity()).updateFromClassNameResource( 328 AccountSettings.class.getName(), true, true); 329 } 330 newAddAccountPreference(Context context)331 private DimmableIconPreference newAddAccountPreference(Context context) { 332 DimmableIconPreference preference = new DimmableIconPreference(getPrefContext()); 333 preference.setTitle(R.string.add_account_label); 334 preference.setIcon(R.drawable.ic_menu_add); 335 preference.setOnPreferenceClickListener(this); 336 preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST); 337 return preference; 338 } 339 newRemoveWorkProfilePreference(Context context)340 private Preference newRemoveWorkProfilePreference(Context context) { 341 Preference preference = new Preference(getPrefContext()); 342 preference.setTitle(R.string.remove_managed_profile_label); 343 preference.setIcon(R.drawable.ic_menu_delete); 344 preference.setOnPreferenceClickListener(this); 345 preference.setOrder(ORDER_LAST); 346 return preference; 347 } 348 349 newManagedProfileSettings()350 private Preference newManagedProfileSettings() { 351 Preference preference = new Preference(getPrefContext()); 352 preference.setTitle(R.string.managed_profile_settings_title); 353 preference.setIcon(R.drawable.ic_sysbar_quicksettings); 354 preference.setOnPreferenceClickListener(this); 355 preference.setOrder(ORDER_NEXT_TO_LAST); 356 return preference; 357 } 358 getWorkGroupSummary(Context context, UserInfo userInfo)359 private String getWorkGroupSummary(Context context, UserInfo userInfo) { 360 PackageManager packageManager = context.getPackageManager(); 361 ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id); 362 if (adminApplicationInfo == null) { 363 return null; 364 } 365 CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo); 366 return getString(R.string.managing_admin, appLabel); 367 } 368 cleanUpPreferences()369 private void cleanUpPreferences() { 370 PreferenceScreen preferenceScreen = getPreferenceScreen(); 371 if (preferenceScreen != null) { 372 preferenceScreen.removeAll(); 373 } 374 mProfiles.clear(); 375 } 376 listenToAccountUpdates()377 private void listenToAccountUpdates() { 378 final int count = mProfiles.size(); 379 for (int i = 0; i < count; i++) { 380 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper; 381 if (authenticatorHelper != null) { 382 authenticatorHelper.listenToAccountUpdates(); 383 } 384 } 385 } 386 stopListeningToAccountUpdates()387 private void stopListeningToAccountUpdates() { 388 final int count = mProfiles.size(); 389 for (int i = 0; i < count; i++) { 390 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper; 391 if (authenticatorHelper != null) { 392 authenticatorHelper.stopListeningToAccountUpdates(); 393 } 394 } 395 } 396 updateAccountTypes(ProfileData profileData)397 private void updateAccountTypes(ProfileData profileData) { 398 profileData.preferenceGroup.removeAll(); 399 if (profileData.userInfo.isEnabled()) { 400 final ArrayList<AccountPreference> preferences = getAccountTypePreferences( 401 profileData.authenticatorHelper, profileData.userInfo.getUserHandle()); 402 final int count = preferences.size(); 403 for (int i = 0; i < count; i++) { 404 profileData.preferenceGroup.addPreference(preferences.get(i)); 405 } 406 if (profileData.addAccountPreference != null) { 407 profileData.preferenceGroup.addPreference(profileData.addAccountPreference); 408 } 409 } else { 410 // Put a label instead of the accounts list 411 mProfileNotAvailablePreference.setEnabled(false); 412 mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon); 413 mProfileNotAvailablePreference.setTitle(null); 414 mProfileNotAvailablePreference.setSummary( 415 R.string.managed_profile_not_available_label); 416 profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference); 417 } 418 if (profileData.removeWorkProfilePreference != null) { 419 profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference); 420 } 421 if (profileData.managedProfilePreference != null) { 422 profileData.preferenceGroup.addPreference(profileData.managedProfilePreference); 423 } 424 } 425 getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle)426 private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper, 427 UserHandle userHandle) { 428 final String[] accountTypes = helper.getEnabledAccountTypes(); 429 final ArrayList<AccountPreference> accountTypePreferences = 430 new ArrayList<AccountPreference>(accountTypes.length); 431 432 for (int i = 0; i < accountTypes.length; i++) { 433 final String accountType = accountTypes[i]; 434 // Skip showing any account that does not have any of the requested authorities 435 if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) { 436 continue; 437 } 438 final CharSequence label = helper.getLabelForType(getActivity(), accountType); 439 if (label == null) { 440 continue; 441 } 442 final String titleResPackageName = helper.getPackageForType(accountType); 443 final int titleResId = helper.getLabelIdForType(accountType); 444 445 final Account[] accounts = AccountManager.get(getActivity()) 446 .getAccountsByTypeAsUser(accountType, userHandle); 447 final boolean skipToAccount = accounts.length == 1 448 && !helper.hasAccountPreferences(accountType); 449 450 if (skipToAccount) { 451 final Bundle fragmentArguments = new Bundle(); 452 fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY, 453 accounts[0]); 454 fragmentArguments.putParcelable(EXTRA_USER, userHandle); 455 456 accountTypePreferences.add(new AccountPreference(getPrefContext(), label, 457 titleResPackageName, titleResId, AccountSyncSettings.class.getName(), 458 fragmentArguments, 459 helper.getDrawableForType(getActivity(), accountType))); 460 } else { 461 final Bundle fragmentArguments = new Bundle(); 462 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); 463 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, 464 label.toString()); 465 fragmentArguments.putParcelable(EXTRA_USER, userHandle); 466 467 accountTypePreferences.add(new AccountPreference(getPrefContext(), label, 468 titleResPackageName, titleResId, ManageAccountsSettings.class.getName(), 469 fragmentArguments, 470 helper.getDrawableForType(getActivity(), accountType))); 471 } 472 helper.preloadDrawableForType(getActivity(), accountType); 473 } 474 // Sort by label 475 Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() { 476 @Override 477 public int compare(AccountPreference t1, AccountPreference t2) { 478 return t1.mTitle.toString().compareTo(t2.mTitle.toString()); 479 } 480 }); 481 return accountTypePreferences; 482 } 483 accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)484 private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, 485 String accountType) { 486 if (mAuthoritiesCount == 0) { 487 // No authorities required 488 return true; 489 } 490 final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType( 491 accountType); 492 if (authoritiesForType == null) { 493 Log.d(TAG, "No sync authorities for account type: " + accountType); 494 return false; 495 } 496 for (int j = 0; j < mAuthoritiesCount; j++) { 497 if (authoritiesForType.contains(mAuthorities[j])) { 498 return true; 499 } 500 } 501 return false; 502 } 503 504 private class AccountPreference extends Preference implements OnPreferenceClickListener { 505 /** 506 * Title of the tile that is shown to the user. 507 * @attr ref android.R.styleable#PreferenceHeader_title 508 */ 509 private final CharSequence mTitle; 510 511 /** 512 * Packange name used to resolve the resources of the title shown to the user in the new 513 * fragment. 514 */ 515 private final String mTitleResPackageName; 516 517 /** 518 * Resource id of the title shown to the user in the new fragment. 519 */ 520 private final int mTitleResId; 521 522 /** 523 * Full class name of the fragment to display when this tile is 524 * selected. 525 * @attr ref android.R.styleable#PreferenceHeader_fragment 526 */ 527 private final String mFragment; 528 529 /** 530 * Optional arguments to supply to the fragment when it is 531 * instantiated. 532 */ 533 private final Bundle mFragmentArguments; 534 AccountPreference(Context context, CharSequence title, String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments, Drawable icon)535 public AccountPreference(Context context, CharSequence title, String titleResPackageName, 536 int titleResId, String fragment, Bundle fragmentArguments, 537 Drawable icon) { 538 super(context); 539 mTitle = title; 540 mTitleResPackageName = titleResPackageName; 541 mTitleResId = titleResId; 542 mFragment = fragment; 543 mFragmentArguments = fragmentArguments; 544 setWidgetLayoutResource(R.layout.account_type_preference); 545 546 setTitle(title); 547 setIcon(icon); 548 549 setOnPreferenceClickListener(this); 550 } 551 552 @Override onPreferenceClick(Preference preference)553 public boolean onPreferenceClick(Preference preference) { 554 if (mFragment != null) { 555 Utils.startWithFragment(getContext(), mFragment, mFragmentArguments, 556 null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName, 557 mTitleResId, null /* title */); 558 return true; 559 } 560 return false; 561 } 562 } 563 564 private class ManagedProfileBroadcastReceiver extends BroadcastReceiver { 565 private boolean listeningToManagedProfileEvents; 566 567 @Override onReceive(Context context, Intent intent)568 public void onReceive(Context context, Intent intent) { 569 final String action = intent.getAction(); 570 Log.v(TAG, "Received broadcast: " + action); 571 if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED) 572 || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) { 573 // Clean old state 574 stopListeningToAccountUpdates(); 575 cleanUpPreferences(); 576 // Build new state 577 updateUi(); 578 listenToAccountUpdates(); 579 // Force the menu to update. Note that #onPrepareOptionsMenu uses data built by 580 // #updateUi so we must call this later 581 getActivity().invalidateOptionsMenu(); 582 return; 583 } 584 Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction()); 585 } 586 register(Context context)587 public void register(Context context) { 588 if (!listeningToManagedProfileEvents) { 589 IntentFilter intentFilter = new IntentFilter(); 590 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 591 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 592 context.registerReceiver(this, intentFilter); 593 listeningToManagedProfileEvents = true; 594 } 595 } 596 unregister(Context context)597 public void unregister(Context context) { 598 if (listeningToManagedProfileEvents) { 599 context.unregisterReceiver(this); 600 listeningToManagedProfileEvents = false; 601 } 602 } 603 } 604 605 private class MasterSyncStateClickListener implements MenuItem.OnMenuItemClickListener { 606 private final UserHandle mUserHandle; 607 MasterSyncStateClickListener(UserHandle userHandle)608 public MasterSyncStateClickListener(UserHandle userHandle) { 609 mUserHandle = userHandle; 610 } 611 612 @Override onMenuItemClick(MenuItem item)613 public boolean onMenuItemClick(MenuItem item) { 614 if (ActivityManager.isUserAMonkey()) { 615 Log.d(TAG, "ignoring monkey's attempt to flip sync state"); 616 } else { 617 ConfirmAutoSyncChangeFragment.show(AccountSettings.this, !item.isChecked(), 618 mUserHandle); 619 } 620 return true; 621 } 622 } 623 624 /** 625 * Dialog to inform user about changing auto-sync setting 626 */ 627 public static class ConfirmAutoSyncChangeFragment extends DialogFragment { 628 private static final String SAVE_ENABLING = "enabling"; 629 private static final String SAVE_USER_HANDLE = "userHandle"; 630 private boolean mEnabling; 631 private UserHandle mUserHandle; 632 show(AccountSettings parent, boolean enabling, UserHandle userHandle)633 public static void show(AccountSettings parent, boolean enabling, UserHandle userHandle) { 634 if (!parent.isAdded()) return; 635 636 final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment(); 637 dialog.mEnabling = enabling; 638 dialog.mUserHandle = userHandle; 639 dialog.setTargetFragment(parent, 0); 640 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE); 641 } 642 643 @Override onCreateDialog(Bundle savedInstanceState)644 public Dialog onCreateDialog(Bundle savedInstanceState) { 645 final Context context = getActivity(); 646 if (savedInstanceState != null) { 647 mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING); 648 mUserHandle = (UserHandle) savedInstanceState.getParcelable(SAVE_USER_HANDLE); 649 } 650 651 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 652 if (!mEnabling) { 653 builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title); 654 builder.setMessage(R.string.data_usage_auto_sync_off_dialog); 655 } else { 656 builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title); 657 builder.setMessage(R.string.data_usage_auto_sync_on_dialog); 658 } 659 660 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 661 @Override 662 public void onClick(DialogInterface dialog, int which) { 663 ContentResolver.setMasterSyncAutomaticallyAsUser(mEnabling, 664 mUserHandle.getIdentifier()); 665 } 666 }); 667 builder.setNegativeButton(android.R.string.cancel, null); 668 669 return builder.create(); 670 } 671 672 @Override onSaveInstanceState(Bundle outState)673 public void onSaveInstanceState(Bundle outState) { 674 super.onSaveInstanceState(outState); 675 outState.putBoolean(SAVE_ENABLING, mEnabling); 676 outState.putParcelable(SAVE_USER_HANDLE, mUserHandle); 677 } 678 } 679 680 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 681 new BaseSearchIndexProvider() { 682 @Override 683 public List<SearchIndexableResource> getXmlResourcesToIndex( 684 Context context, boolean enabled) { 685 final SearchIndexableResource sir = new SearchIndexableResource(context); 686 sir.xmlResId = R.xml.account_settings; 687 return Arrays.asList(sir); 688 } 689 690 @Override 691 public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { 692 final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(); 693 final Resources res = context.getResources(); 694 final String screenTitle = res.getString(R.string.account_settings_title); 695 696 final UserManager um = UserManager.get(context); 697 List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId()); 698 final int profilesCount = profiles.size(); 699 for (int i = 0; i < profilesCount; i++) { 700 UserInfo userInfo = profiles.get(i); 701 if (userInfo.isEnabled()) { 702 if (!RestrictedLockUtils.hasBaseUserRestriction(context, 703 DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) { 704 SearchIndexableRaw data = new SearchIndexableRaw(context); 705 data.title = res.getString(R.string.add_account_label); 706 data.screenTitle = screenTitle; 707 result.add(data); 708 } 709 if (userInfo.isManagedProfile()) { 710 { 711 SearchIndexableRaw data = new SearchIndexableRaw(context); 712 data.title = res.getString(R.string.remove_managed_profile_label); 713 data.screenTitle = screenTitle; 714 result.add(data); 715 } 716 { 717 SearchIndexableRaw data = new SearchIndexableRaw(context); 718 data.title = res.getString(R.string.managed_profile_settings_title); 719 data.screenTitle = screenTitle; 720 result.add(data); 721 } 722 } 723 } 724 } 725 return result; 726 } 727 }; 728 } 729