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.v7.preference.Preference;
43import android.support.v7.preference.Preference.OnPreferenceClickListener;
44import android.support.v7.preference.PreferenceGroup;
45import android.support.v7.preference.PreferenceScreen;
46import android.util.Log;
47import android.util.SparseArray;
48import android.view.Menu;
49import android.view.MenuInflater;
50import android.view.MenuItem;
51
52import com.android.internal.logging.MetricsProto.MetricsEvent;
53import com.android.settings.AccessiblePreferenceCategory;
54import com.android.settings.DimmableIconPreference;
55import com.android.settings.R;
56import com.android.settings.SettingsActivity;
57import com.android.settings.SettingsPreferenceFragment;
58import com.android.settings.Utils;
59import com.android.settings.search.BaseSearchIndexProvider;
60import com.android.settings.search.Index;
61import com.android.settings.search.Indexable;
62import com.android.settings.search.SearchIndexableRaw;
63import com.android.settings.users.UserDialogs;
64import com.android.settingslib.RestrictedLockUtils;
65import com.android.settingslib.accounts.AuthenticatorHelper;
66
67import java.util.ArrayList;
68import java.util.Arrays;
69import java.util.Collections;
70import java.util.Comparator;
71import java.util.List;
72
73import static android.content.Intent.EXTRA_USER;
74import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
75import 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 */
84public 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
137    protected int getMetricsCategory() {
138        return MetricsEvent.ACCOUNT;
139    }
140
141    @Override
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
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
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
191    public void onResume() {
192        super.onResume();
193        cleanUpPreferences();
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    }
205
206    @Override
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
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
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
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
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
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
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
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
371    private void cleanUpPreferences() {
372        PreferenceScreen preferenceScreen = getPreferenceScreen();
373        if (preferenceScreen != null) {
374            preferenceScreen.removeAll();
375        }
376        mProfiles.clear();
377    }
378
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
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
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
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
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
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
555        public boolean onPreferenceClick(Preference preference) {
556            if (mFragment != null) {
557                UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER);
558                if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), mUm,
559                        user.getIdentifier())) {
560                    return true;
561                } else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(),
562                        user.getIdentifier())) {
563                    return true;
564                }
565                Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
566                        null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
567                        mTitleResId, null /* title */);
568                return true;
569            }
570            return false;
571        }
572    }
573
574    private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
575        private boolean listeningToManagedProfileEvents;
576
577        @Override
578        public void onReceive(Context context, Intent intent) {
579            final String action = intent.getAction();
580            Log.v(TAG, "Received broadcast: " + action);
581            if (action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)
582                    || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
583                // Clean old state
584                stopListeningToAccountUpdates();
585                cleanUpPreferences();
586                // Build new state
587                updateUi();
588                listenToAccountUpdates();
589                // Force the menu to update. Note that #onPrepareOptionsMenu uses data built by
590                // #updateUi so we must call this later
591                getActivity().invalidateOptionsMenu();
592                return;
593            }
594            Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
595        }
596
597        public void register(Context context) {
598            if (!listeningToManagedProfileEvents) {
599                IntentFilter intentFilter = new IntentFilter();
600                intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
601                intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
602                context.registerReceiver(this, intentFilter);
603                listeningToManagedProfileEvents = true;
604            }
605        }
606
607        public void unregister(Context context) {
608            if (listeningToManagedProfileEvents) {
609                context.unregisterReceiver(this);
610                listeningToManagedProfileEvents = false;
611            }
612        }
613    }
614
615    private class MasterSyncStateClickListener implements MenuItem.OnMenuItemClickListener {
616        private final UserHandle mUserHandle;
617
618        public MasterSyncStateClickListener(UserHandle userHandle) {
619            mUserHandle = userHandle;
620        }
621
622        @Override
623        public boolean onMenuItemClick(MenuItem item) {
624            if (ActivityManager.isUserAMonkey()) {
625                Log.d(TAG, "ignoring monkey's attempt to flip sync state");
626            } else {
627                ConfirmAutoSyncChangeFragment.show(AccountSettings.this, !item.isChecked(),
628                        mUserHandle);
629            }
630            return true;
631        }
632    }
633
634    /**
635     * Dialog to inform user about changing auto-sync setting
636     */
637    public static class ConfirmAutoSyncChangeFragment extends DialogFragment {
638        private static final String SAVE_ENABLING = "enabling";
639        private static final String SAVE_USER_HANDLE = "userHandle";
640        private boolean mEnabling;
641        private UserHandle mUserHandle;
642
643        public static void show(AccountSettings parent, boolean enabling, UserHandle userHandle) {
644            if (!parent.isAdded()) return;
645
646            final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment();
647            dialog.mEnabling = enabling;
648            dialog.mUserHandle = userHandle;
649            dialog.setTargetFragment(parent, 0);
650            dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE);
651        }
652
653        @Override
654        public Dialog onCreateDialog(Bundle savedInstanceState) {
655            final Context context = getActivity();
656            if (savedInstanceState != null) {
657                mEnabling = savedInstanceState.getBoolean(SAVE_ENABLING);
658                mUserHandle = (UserHandle) savedInstanceState.getParcelable(SAVE_USER_HANDLE);
659            }
660
661            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
662            if (!mEnabling) {
663                builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title);
664                builder.setMessage(R.string.data_usage_auto_sync_off_dialog);
665            } else {
666                builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title);
667                builder.setMessage(R.string.data_usage_auto_sync_on_dialog);
668            }
669
670            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
671                @Override
672                public void onClick(DialogInterface dialog, int which) {
673                    ContentResolver.setMasterSyncAutomaticallyAsUser(mEnabling,
674                            mUserHandle.getIdentifier());
675                }
676            });
677            builder.setNegativeButton(android.R.string.cancel, null);
678
679            return builder.create();
680        }
681
682        @Override
683        public void onSaveInstanceState(Bundle outState) {
684            super.onSaveInstanceState(outState);
685            outState.putBoolean(SAVE_ENABLING, mEnabling);
686            outState.putParcelable(SAVE_USER_HANDLE, mUserHandle);
687        }
688    }
689
690    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
691            new BaseSearchIndexProvider() {
692        @Override
693        public List<SearchIndexableResource> getXmlResourcesToIndex(
694                Context context, boolean enabled) {
695            final SearchIndexableResource sir = new SearchIndexableResource(context);
696            sir.xmlResId = R.xml.account_settings;
697            return Arrays.asList(sir);
698        }
699
700        @Override
701        public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
702            final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
703            final Resources res = context.getResources();
704            final String screenTitle = res.getString(R.string.account_settings_title);
705
706            final UserManager um = UserManager.get(context);
707            List<UserInfo> profiles = um.getProfiles(UserHandle.myUserId());
708            final int profilesCount = profiles.size();
709            for (int i = 0; i < profilesCount; i++) {
710                UserInfo userInfo = profiles.get(i);
711                if (userInfo.isEnabled()) {
712                    if (!RestrictedLockUtils.hasBaseUserRestriction(context,
713                            DISALLOW_MODIFY_ACCOUNTS, userInfo.id)) {
714                        SearchIndexableRaw data = new SearchIndexableRaw(context);
715                        data.title = res.getString(R.string.add_account_label);
716                        data.screenTitle = screenTitle;
717                        result.add(data);
718                    }
719                    if (userInfo.isManagedProfile()) {
720                        {
721                            SearchIndexableRaw data = new SearchIndexableRaw(context);
722                            data.title = res.getString(R.string.remove_managed_profile_label);
723                            data.screenTitle = screenTitle;
724                            result.add(data);
725                        }
726                        {
727                            SearchIndexableRaw data = new SearchIndexableRaw(context);
728                            data.title = res.getString(R.string.managed_profile_settings_title);
729                            data.screenTitle = screenTitle;
730                            result.add(data);
731                        }
732                    }
733                }
734            }
735            return result;
736        }
737    };
738}
739