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 profileData.addAccountPreference = newAddAccountPreference(context); 320 if (RestrictedLockUtils.hasBaseUserRestriction(context, 321 UserManager.DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) { 322 profileData.addAccountPreference.setEnabled(false); 323 } else { 324 profileData.addAccountPreference.checkRestrictionAndSetDisabled( 325 DISALLOW_MODIFY_ACCOUNTS, userInfo.id); 326 } 327 } 328 mProfiles.put(userInfo.id, profileData); 329 Index.getInstance(getActivity()).updateFromClassNameResource( 330 AccountSettings.class.getName(), true, true); 331 } 332 newAddAccountPreference(Context context)333 private DimmableIconPreference newAddAccountPreference(Context context) { 334 DimmableIconPreference preference = new DimmableIconPreference(getPrefContext()); 335 preference.setTitle(R.string.add_account_label); 336 preference.setIcon(R.drawable.ic_menu_add); 337 preference.setOnPreferenceClickListener(this); 338 preference.setOrder(ORDER_NEXT_TO_NEXT_TO_LAST); 339 return preference; 340 } 341 newRemoveWorkProfilePreference(Context context)342 private Preference newRemoveWorkProfilePreference(Context context) { 343 Preference preference = new Preference(getPrefContext()); 344 preference.setTitle(R.string.remove_managed_profile_label); 345 preference.setIcon(R.drawable.ic_menu_delete); 346 preference.setOnPreferenceClickListener(this); 347 preference.setOrder(ORDER_LAST); 348 return preference; 349 } 350 351 newManagedProfileSettings()352 private Preference newManagedProfileSettings() { 353 Preference preference = new Preference(getPrefContext()); 354 preference.setTitle(R.string.managed_profile_settings_title); 355 preference.setIcon(R.drawable.ic_settings); 356 preference.setOnPreferenceClickListener(this); 357 preference.setOrder(ORDER_NEXT_TO_LAST); 358 return preference; 359 } 360 getWorkGroupSummary(Context context, UserInfo userInfo)361 private String getWorkGroupSummary(Context context, UserInfo userInfo) { 362 PackageManager packageManager = context.getPackageManager(); 363 ApplicationInfo adminApplicationInfo = Utils.getAdminApplicationInfo(context, userInfo.id); 364 if (adminApplicationInfo == null) { 365 return null; 366 } 367 CharSequence appLabel = packageManager.getApplicationLabel(adminApplicationInfo); 368 return getString(R.string.managing_admin, appLabel); 369 } 370 cleanUpPreferences()371 private void cleanUpPreferences() { 372 PreferenceScreen preferenceScreen = getPreferenceScreen(); 373 if (preferenceScreen != null) { 374 preferenceScreen.removeAll(); 375 } 376 mProfiles.clear(); 377 } 378 listenToAccountUpdates()379 private void listenToAccountUpdates() { 380 final int count = mProfiles.size(); 381 for (int i = 0; i < count; i++) { 382 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper; 383 if (authenticatorHelper != null) { 384 authenticatorHelper.listenToAccountUpdates(); 385 } 386 } 387 } 388 stopListeningToAccountUpdates()389 private void stopListeningToAccountUpdates() { 390 final int count = mProfiles.size(); 391 for (int i = 0; i < count; i++) { 392 AuthenticatorHelper authenticatorHelper = mProfiles.valueAt(i).authenticatorHelper; 393 if (authenticatorHelper != null) { 394 authenticatorHelper.stopListeningToAccountUpdates(); 395 } 396 } 397 } 398 updateAccountTypes(ProfileData profileData)399 private void updateAccountTypes(ProfileData profileData) { 400 profileData.preferenceGroup.removeAll(); 401 if (profileData.userInfo.isEnabled()) { 402 final ArrayList<AccountPreference> preferences = getAccountTypePreferences( 403 profileData.authenticatorHelper, profileData.userInfo.getUserHandle()); 404 final int count = preferences.size(); 405 for (int i = 0; i < count; i++) { 406 profileData.preferenceGroup.addPreference(preferences.get(i)); 407 } 408 if (profileData.addAccountPreference != null) { 409 profileData.preferenceGroup.addPreference(profileData.addAccountPreference); 410 } 411 } else { 412 // Put a label instead of the accounts list 413 mProfileNotAvailablePreference.setEnabled(false); 414 mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon); 415 mProfileNotAvailablePreference.setTitle(null); 416 mProfileNotAvailablePreference.setSummary( 417 R.string.managed_profile_not_available_label); 418 profileData.preferenceGroup.addPreference(mProfileNotAvailablePreference); 419 } 420 if (profileData.removeWorkProfilePreference != null) { 421 profileData.preferenceGroup.addPreference(profileData.removeWorkProfilePreference); 422 } 423 if (profileData.managedProfilePreference != null) { 424 profileData.preferenceGroup.addPreference(profileData.managedProfilePreference); 425 } 426 } 427 getAccountTypePreferences(AuthenticatorHelper helper, UserHandle userHandle)428 private ArrayList<AccountPreference> getAccountTypePreferences(AuthenticatorHelper helper, 429 UserHandle userHandle) { 430 final String[] accountTypes = helper.getEnabledAccountTypes(); 431 final ArrayList<AccountPreference> accountTypePreferences = 432 new ArrayList<AccountPreference>(accountTypes.length); 433 434 for (int i = 0; i < accountTypes.length; i++) { 435 final String accountType = accountTypes[i]; 436 // Skip showing any account that does not have any of the requested authorities 437 if (!accountTypeHasAnyRequestedAuthorities(helper, accountType)) { 438 continue; 439 } 440 final CharSequence label = helper.getLabelForType(getActivity(), accountType); 441 if (label == null) { 442 continue; 443 } 444 final String titleResPackageName = helper.getPackageForType(accountType); 445 final int titleResId = helper.getLabelIdForType(accountType); 446 447 final Account[] accounts = AccountManager.get(getActivity()) 448 .getAccountsByTypeAsUser(accountType, userHandle); 449 final boolean skipToAccount = accounts.length == 1 450 && !helper.hasAccountPreferences(accountType); 451 452 if (skipToAccount) { 453 final Bundle fragmentArguments = new Bundle(); 454 fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY, 455 accounts[0]); 456 fragmentArguments.putParcelable(EXTRA_USER, userHandle); 457 458 accountTypePreferences.add(new AccountPreference(getPrefContext(), label, 459 titleResPackageName, titleResId, AccountSyncSettings.class.getName(), 460 fragmentArguments, 461 helper.getDrawableForType(getActivity(), accountType))); 462 } else { 463 final Bundle fragmentArguments = new Bundle(); 464 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); 465 fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, 466 label.toString()); 467 fragmentArguments.putParcelable(EXTRA_USER, userHandle); 468 469 accountTypePreferences.add(new AccountPreference(getPrefContext(), label, 470 titleResPackageName, titleResId, ManageAccountsSettings.class.getName(), 471 fragmentArguments, 472 helper.getDrawableForType(getActivity(), accountType))); 473 } 474 helper.preloadDrawableForType(getActivity(), accountType); 475 } 476 // Sort by label 477 Collections.sort(accountTypePreferences, new Comparator<AccountPreference>() { 478 @Override 479 public int compare(AccountPreference t1, AccountPreference t2) { 480 return t1.mTitle.toString().compareTo(t2.mTitle.toString()); 481 } 482 }); 483 return accountTypePreferences; 484 } 485 accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, String accountType)486 private boolean accountTypeHasAnyRequestedAuthorities(AuthenticatorHelper helper, 487 String accountType) { 488 if (mAuthoritiesCount == 0) { 489 // No authorities required 490 return true; 491 } 492 final ArrayList<String> authoritiesForType = helper.getAuthoritiesForAccountType( 493 accountType); 494 if (authoritiesForType == null) { 495 Log.d(TAG, "No sync authorities for account type: " + accountType); 496 return false; 497 } 498 for (int j = 0; j < mAuthoritiesCount; j++) { 499 if (authoritiesForType.contains(mAuthorities[j])) { 500 return true; 501 } 502 } 503 return false; 504 } 505 506 private class AccountPreference extends Preference implements OnPreferenceClickListener { 507 /** 508 * Title of the tile that is shown to the user. 509 * @attr ref android.R.styleable#PreferenceHeader_title 510 */ 511 private final CharSequence mTitle; 512 513 /** 514 * Packange name used to resolve the resources of the title shown to the user in the new 515 * fragment. 516 */ 517 private final String mTitleResPackageName; 518 519 /** 520 * Resource id of the title shown to the user in the new fragment. 521 */ 522 private final int mTitleResId; 523 524 /** 525 * Full class name of the fragment to display when this tile is 526 * selected. 527 * @attr ref android.R.styleable#PreferenceHeader_fragment 528 */ 529 private final String mFragment; 530 531 /** 532 * Optional arguments to supply to the fragment when it is 533 * instantiated. 534 */ 535 private final Bundle mFragmentArguments; 536 AccountPreference(Context context, CharSequence title, String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments, Drawable icon)537 public AccountPreference(Context context, CharSequence title, String titleResPackageName, 538 int titleResId, String fragment, Bundle fragmentArguments, 539 Drawable icon) { 540 super(context); 541 mTitle = title; 542 mTitleResPackageName = titleResPackageName; 543 mTitleResId = titleResId; 544 mFragment = fragment; 545 mFragmentArguments = fragmentArguments; 546 setWidgetLayoutResource(R.layout.account_type_preference); 547 548 setTitle(title); 549 setIcon(icon); 550 551 setOnPreferenceClickListener(this); 552 } 553 554 @Override onPreferenceClick(Preference preference)555 public boolean onPreferenceClick(Preference preference) { 556 if (mFragment != null) { 557 Utils.startWithFragment(getContext(), mFragment, mFragmentArguments, 558 null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName, 559 mTitleResId, null /* title */); 560 return true; 561 } 562 return false; 563 } 564 } 565 566 private class ManagedProfileBroadcastReceiver extends BroadcastReceiver { 567 private boolean listeningToManagedProfileEvents; 568 569 @Override onReceive(Context context, Intent intent)570 public void onReceive(Context context, Intent intent) { 571 final String action = intent.getAction(); 572 Log.v(TAG, "Received broadcast: " + action); 573 if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED) 574 || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) { 575 // Clean old state 576 stopListeningToAccountUpdates(); 577 cleanUpPreferences(); 578 // Build new state 579 updateUi(); 580 listenToAccountUpdates(); 581 // Force the menu to update. Note that #onPrepareOptionsMenu uses data built by 582 // #updateUi so we must call this later 583 getActivity().invalidateOptionsMenu(); 584 return; 585 } 586 Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction()); 587 } 588 register(Context context)589 public void register(Context context) { 590 if (!listeningToManagedProfileEvents) { 591 IntentFilter intentFilter = new IntentFilter(); 592 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 593 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 594 context.registerReceiver(this, intentFilter); 595 listeningToManagedProfileEvents = true; 596 } 597 } 598 unregister(Context context)599 public void unregister(Context context) { 600 if (listeningToManagedProfileEvents) { 601 context.unregisterReceiver(this); 602 listeningToManagedProfileEvents = false; 603 } 604 } 605 } 606 607 private class MasterSyncStateClickListener implements MenuItem.OnMenuItemClickListener { 608 private final UserHandle mUserHandle; 609 MasterSyncStateClickListener(UserHandle userHandle)610 public MasterSyncStateClickListener(UserHandle userHandle) { 611 mUserHandle = userHandle; 612 } 613 614 @Override onMenuItemClick(MenuItem item)615 public boolean onMenuItemClick(MenuItem item) { 616 if (ActivityManager.isUserAMonkey()) { 617 Log.d(TAG, "ignoring monkey's attempt to flip sync state"); 618 } else { 619 ConfirmAutoSyncChangeFragment.show(AccountSettings.this, !item.isChecked(), 620 mUserHandle); 621 } 622 return true; 623 } 624 } 625 626 /** 627 * Dialog to inform user about changing auto-sync setting 628 */ 629 public static class ConfirmAutoSyncChangeFragment extends DialogFragment { 630 private static final String SAVE_ENABLING = "enabling"; 631 private static final String SAVE_USER_HANDLE = "userHandle"; 632 private boolean mEnabling; 633 private UserHandle mUserHandle; 634 show(AccountSettings parent, boolean enabling, UserHandle userHandle)635 public static void show(AccountSettings parent, boolean enabling, UserHandle userHandle) { 636 if (!parent.isAdded()) return; 637 638 final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment(); 639 dialog.mEnabling = enabling; 640 dialog.mUserHandle = userHandle; 641 dialog.setTargetFragment(parent, 0); 642 dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE); 643 } 644 645 @Override onCreateDialog(Bundle savedInstanceState)646 public Dialog onCreateDialog(Bundle savedInstanceState) { 647 final Context context = getActivity(); 648 if (savedInstanceState != null) { 649 mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING); 650 mUserHandle = (UserHandle) savedInstanceState.getParcelable(SAVE_USER_HANDLE); 651 } 652 653 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 654 if (!mEnabling) { 655 builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title); 656 builder.setMessage(R.string.data_usage_auto_sync_off_dialog); 657 } else { 658 builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title); 659 builder.setMessage(R.string.data_usage_auto_sync_on_dialog); 660 } 661 662 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 663 @Override 664 public void onClick(DialogInterface dialog, int which) { 665 ContentResolver.setMasterSyncAutomaticallyAsUser(mEnabling, 666 mUserHandle.getIdentifier()); 667 } 668 }); 669 builder.setNegativeButton(android.R.string.cancel, null); 670 671 return builder.create(); 672 } 673 674 @Override onSaveInstanceState(Bundle outState)675 public void onSaveInstanceState(Bundle outState) { 676 super.onSaveInstanceState(outState); 677 outState.putBoolean(SAVE_ENABLING, mEnabling); 678 outState.putParcelable(SAVE_USER_HANDLE, mUserHandle); 679 } 680 } 681 682 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 683 new BaseSearchIndexProvider() { 684 @Override 685 public List<SearchIndexableResource> getXmlResourcesToIndex( 686 Context context, boolean enabled) { 687 final SearchIndexableResource sir = new SearchIndexableResource(context); 688 sir.xmlResId = R.xml.account_settings; 689 return Arrays.asList(sir); 690 } 691 692 @Override 693 public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { 694 final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(); 695 final Resources res = context.getResources(); 696 final String screenTitle = res.getString(R.string.account_settings_title); 697 698 final UserManager um = UserManager.get(context); 699 List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId()); 700 final int profilesCount = profiles.size(); 701 for (int i = 0; i < profilesCount; i++) { 702 UserInfo userInfo = profiles.get(i); 703 if (userInfo.isEnabled()) { 704 if (!RestrictedLockUtils.hasBaseUserRestriction(context, 705 DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) { 706 SearchIndexableRaw data = new SearchIndexableRaw(context); 707 data.title = res.getString(R.string.add_account_label); 708 data.screenTitle = screenTitle; 709 result.add(data); 710 } 711 if (userInfo.isManagedProfile()) { 712 { 713 SearchIndexableRaw data = new SearchIndexableRaw(context); 714 data.title = res.getString(R.string.remove_managed_profile_label); 715 data.screenTitle = screenTitle; 716 result.add(data); 717 } 718 { 719 SearchIndexableRaw data = new SearchIndexableRaw(context); 720 data.title = res.getString(R.string.managed_profile_settings_title); 721 data.screenTitle = screenTitle; 722 result.add(data); 723 } 724 } 725 } 726 } 727 return result; 728 } 729 }; 730 } 731