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