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