• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_WORK_ACCOUNT_TITLE;
21 
22 import android.accounts.Account;
23 import android.accounts.AccountManager;
24 import android.app.Activity;
25 import android.app.Dialog;
26 import android.app.admin.DevicePolicyManager;
27 import android.app.settings.SettingsEnums;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentSender;
32 import android.content.SyncAdapterType;
33 import android.content.SyncInfo;
34 import android.content.SyncStatusInfo;
35 import android.content.pm.PackageManager;
36 import android.content.pm.ProviderInfo;
37 import android.content.pm.UserInfo;
38 import android.os.Binder;
39 import android.os.Bundle;
40 import android.os.UserHandle;
41 import android.os.UserManager;
42 import android.text.TextUtils;
43 import android.text.format.DateUtils;
44 import android.util.Log;
45 import android.view.Menu;
46 import android.view.MenuInflater;
47 import android.view.MenuItem;
48 
49 import androidx.annotation.VisibleForTesting;
50 import androidx.appcompat.app.AlertDialog;
51 import androidx.preference.Preference;
52 
53 import com.android.settings.R;
54 import com.android.settings.Utils;
55 import com.android.settings.widget.EntityHeaderController;
56 import com.android.settingslib.widget.FooterPreference;
57 
58 import com.google.android.collect.Lists;
59 
60 import java.util.ArrayList;
61 import java.util.Date;
62 import java.util.HashMap;
63 import java.util.List;
64 
65 public class AccountSyncSettings extends AccountPreferenceBase {
66 
67     public static final String ACCOUNT_KEY = "account";
68     private static final int MENU_SYNC_NOW_ID = Menu.FIRST;
69     private static final int MENU_SYNC_CANCEL_ID = Menu.FIRST + 1;
70     private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;
71     private static final String UID_REQUEST_KEY = "uid_request_code";
72 
73     private Account mAccount;
74     private ArrayList<SyncAdapterType> mInvisibleAdapters = Lists.newArrayList();
75     private HashMap<Integer, Integer> mUidRequestCodeMap = new HashMap<>();
76 
77     @Override
onCreateDialog(final int id)78     public Dialog onCreateDialog(final int id) {
79         Dialog dialog = null;
80         if (id == CANT_DO_ONETIME_SYNC_DIALOG) {
81             dialog = new AlertDialog.Builder(getActivity())
82                     .setTitle(R.string.cant_sync_dialog_title)
83                     .setMessage(R.string.cant_sync_dialog_message)
84                     .setPositiveButton(android.R.string.ok, null)
85                     .create();
86         }
87         return dialog;
88     }
89 
90     @Override
getMetricsCategory()91     public int getMetricsCategory() {
92         return SettingsEnums.ACCOUNTS_ACCOUNT_SYNC;
93     }
94 
95     @Override
getDialogMetricsCategory(int dialogId)96     public int getDialogMetricsCategory(int dialogId) {
97         switch (dialogId) {
98             case CANT_DO_ONETIME_SYNC_DIALOG:
99                 return SettingsEnums.DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC;
100             default:
101                 return 0;
102         }
103     }
104 
105     @Override
onCreate(Bundle icicle)106     public void onCreate(Bundle icicle) {
107         super.onCreate(icicle);
108         addPreferencesFromResource(R.xml.account_sync_settings);
109         getPreferenceScreen().setOrderingAsAdded(false);
110         setAccessibilityTitle();
111     }
112 
113     @Override
onSaveInstanceState(Bundle outState)114     public void onSaveInstanceState(Bundle outState) {
115         super.onSaveInstanceState(outState);
116         if (!mUidRequestCodeMap.isEmpty()) {
117             outState.putSerializable(UID_REQUEST_KEY, mUidRequestCodeMap);
118         }
119     }
120 
121     @Override
onActivityCreated(Bundle savedInstanceState)122     public void onActivityCreated(Bundle savedInstanceState) {
123         super.onActivityCreated(savedInstanceState);
124 
125         Bundle arguments = getArguments();
126         if (arguments == null) {
127             Log.e(TAG, "No arguments provided when starting intent. ACCOUNT_KEY needed.");
128             finish();
129             return;
130         }
131         mAccount = arguments.getParcelable(ACCOUNT_KEY);
132         if (!accountExists(mAccount)) {
133             Log.e(TAG, "Account provided does not exist: " + mAccount);
134             finish();
135             return;
136         }
137         if (Log.isLoggable(TAG, Log.VERBOSE)) {
138             Log.v(TAG, "Got account: " + mAccount);
139         }
140         final Activity activity = getActivity();
141         final Preference pref = EntityHeaderController
142                 .newInstance(activity, this, null /* header */)
143                 .setRecyclerView(getListView(), getSettingsLifecycle())
144                 .setIcon(getDrawableForType(mAccount.type))
145                 .setLabel(mAccount.name)
146                 .setSummary(getLabelForType(mAccount.type))
147                 .done(activity, getPrefContext());
148         pref.setOrder(0);
149         getPreferenceScreen().addPreference(pref);
150         if (savedInstanceState != null && savedInstanceState.containsKey(UID_REQUEST_KEY)) {
151             mUidRequestCodeMap = (HashMap<Integer, Integer>) savedInstanceState.getSerializable(
152                     UID_REQUEST_KEY);
153         }
154     }
155 
setAccessibilityTitle()156     private void setAccessibilityTitle() {
157         final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
158         UserInfo user = um.getUserInfo(mUserHandle.getIdentifier());
159         boolean isWorkProfile = user != null ? user.isManagedProfile() : false;
160         CharSequence currentTitle = getActivity().getTitle();
161 
162         DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
163 
164         String accessibilityTitle =
165                 isWorkProfile
166                         ? devicePolicyManager.getResources().getString(
167                                 ACCESSIBILITY_WORK_ACCOUNT_TITLE,
168                                 () -> getString(R.string.accessibility_work_account_title,
169                                         currentTitle), currentTitle)
170                                 : devicePolicyManager.getResources().getString(
171                                         ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE,
172                                         () -> getString(
173                                                 R.string.accessibility_personal_account_title,
174                                                 currentTitle), currentTitle);
175 
176         getActivity().setTitle(Utils.createAccessibleSequence(currentTitle, accessibilityTitle));
177     }
178 
179     @Override
onResume()180     public void onResume() {
181         mAuthenticatorHelper.listenToAccountUpdates();
182         updateAuthDescriptions();
183         onAccountsUpdate(Binder.getCallingUserHandle());
184         super.onResume();
185     }
186 
187     @Override
onPause()188     public void onPause() {
189         super.onPause();
190         mAuthenticatorHelper.stopListeningToAccountUpdates();
191     }
192 
addSyncStateSwitch(Account account, String authority, String packageName, int uid)193     private void addSyncStateSwitch(Account account, String authority,
194             String packageName, int uid) {
195         SyncStateSwitchPreference item = (SyncStateSwitchPreference) getCachedPreference(authority);
196         if (item == null) {
197             item = new SyncStateSwitchPreference(getPrefContext(), account, authority,
198                     packageName, uid);
199             getPreferenceScreen().addPreference(item);
200         } else {
201             item.setup(account, authority, packageName, uid);
202         }
203         final PackageManager packageManager = getPackageManager();
204         item.setPersistent(false);
205         final ProviderInfo providerInfo = packageManager.resolveContentProviderAsUser(
206                 authority, 0, mUserHandle.getIdentifier());
207         if (providerInfo == null) {
208             return;
209         }
210         final CharSequence providerLabel = providerInfo.loadLabel(packageManager);
211         if (TextUtils.isEmpty(providerLabel)) {
212             Log.e(TAG, "Provider needs a label for authority '" + authority + "'");
213             return;
214         }
215         item.setTitle(providerLabel);
216         item.setKey(authority);
217     }
218 
219     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)220     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
221         MenuItem syncNow = menu.add(0, MENU_SYNC_NOW_ID, 0,
222                 getString(R.string.sync_menu_sync_now));
223         MenuItem syncCancel = menu.add(0, MENU_SYNC_CANCEL_ID, 0,
224                 getString(R.string.sync_menu_sync_cancel));
225 
226         syncNow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER |
227                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
228         syncCancel.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER |
229                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
230 
231         super.onCreateOptionsMenu(menu, inflater);
232     }
233 
234     @Override
onPrepareOptionsMenu(Menu menu)235     public void onPrepareOptionsMenu(Menu menu) {
236         super.onPrepareOptionsMenu(menu);
237         // Note that this also counts accounts that are not currently displayed
238         boolean syncActive = !ContentResolver.getCurrentSyncsAsUser(
239                 mUserHandle.getIdentifier()).isEmpty();
240         menu.findItem(MENU_SYNC_NOW_ID).setVisible(!syncActive).setEnabled(enabledSyncNowMenu());
241         menu.findItem(MENU_SYNC_CANCEL_ID).setVisible(syncActive);
242     }
243 
244     @Override
onOptionsItemSelected(MenuItem item)245     public boolean onOptionsItemSelected(MenuItem item) {
246         switch (item.getItemId()) {
247             case MENU_SYNC_NOW_ID:
248                 startSyncForEnabledProviders();
249                 return true;
250             case MENU_SYNC_CANCEL_ID:
251                 cancelSyncForEnabledProviders();
252                 return true;
253         }
254         return super.onOptionsItemSelected(item);
255     }
256 
257     @Override
onActivityResult(int requestCode, int resultCode, Intent data)258     public void onActivityResult(int requestCode, int resultCode, Intent data) {
259         if (resultCode == Activity.RESULT_OK) {
260             final int count = getPreferenceScreen().getPreferenceCount();
261             for (int i = 0; i < count; i++) {
262                 Preference preference = getPreferenceScreen().getPreference(i);
263                 if (preference instanceof SyncStateSwitchPreference) {
264                     SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
265                     if (getRequestCodeByUid(syncPref.getUid()) == requestCode) {
266                         onPreferenceTreeClick(syncPref);
267                         return;
268                     }
269                 }
270             }
271         }
272     }
273 
274     @Override
onPreferenceTreeClick(Preference preference)275     public boolean onPreferenceTreeClick(Preference preference) {
276         if (getActivity() == null) {
277             return false;
278         }
279         if (preference instanceof SyncStateSwitchPreference) {
280             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
281             final String authority = syncPref.getAuthority();
282             if (TextUtils.isEmpty(authority)) {
283                 return false;
284             }
285             final Account account = syncPref.getAccount();
286             final int userId = mUserHandle.getIdentifier();
287             final String packageName = syncPref.getPackageName();
288 
289             boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
290                     authority, userId);
291             if (syncPref.isOneTimeSyncMode()) {
292                 // If the sync adapter doesn't have access to the account we either
293                 // request access by starting an activity if possible or kick off the
294                 // sync which will end up posting an access request notification.
295                 if (requestAccountAccessIfNeeded(packageName)) {
296                     return true;
297                 }
298                 requestOrCancelSync(account, authority, true);
299             } else {
300                 boolean syncOn = syncPref.isChecked();
301                 boolean oldSyncState = syncAutomatically;
302                 if (syncOn != oldSyncState) {
303                     // Toggling this switch triggers sync but we may need a user approval.
304                     // If the sync adapter doesn't have access to the account we either
305                     // request access by starting an activity if possible or kick off the
306                     // sync which will end up posting an access request notification.
307                     if (syncOn && requestAccountAccessIfNeeded(packageName)) {
308                         return true;
309                     }
310                     // if we're enabling sync, this will request a sync as well
311                     ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
312                     // if the primary sync switch is off, the request above will
313                     // get dropped.  when the user clicks on this toggle,
314                     // we want to force the sync, however.
315                     if (!ContentResolver.getMasterSyncAutomaticallyAsUser(userId) || !syncOn) {
316                         requestOrCancelSync(account, authority, syncOn);
317                     }
318                 }
319             }
320             return true;
321         } else {
322             return super.onPreferenceTreeClick(preference);
323         }
324     }
325 
requestAccountAccessIfNeeded(String packageName)326     private boolean requestAccountAccessIfNeeded(String packageName) {
327         if (packageName == null) {
328             return false;
329         }
330 
331         final int uid;
332         try {
333             uid = getContext().getPackageManager().getPackageUidAsUser(
334                     packageName, mUserHandle.getIdentifier());
335         } catch (PackageManager.NameNotFoundException e) {
336             Log.e(TAG, "Invalid sync ", e);
337             return false;
338         }
339 
340         AccountManager accountManager = getContext().getSystemService(AccountManager.class);
341         if (!accountManager.hasAccountAccess(mAccount, packageName, mUserHandle)) {
342             IntentSender intent = accountManager.createRequestAccountAccessIntentSenderAsUser(
343                     mAccount, packageName, mUserHandle);
344             if (intent != null) {
345                 try {
346                     final int requestCode = addUidAndGenerateRequestCode(uid);
347                     startIntentSenderForResult(intent, requestCode, null /* fillInIntent */, 0, 0,
348                             0, null /* options */);
349                     return true;
350                 } catch (IntentSender.SendIntentException e) {
351                     Log.e(TAG, "Error requesting account access", e);
352                 }
353             }
354         }
355         return false;
356     }
357 
startSyncForEnabledProviders()358     private void startSyncForEnabledProviders() {
359         requestOrCancelSyncForEnabledProviders(true /* start them */);
360         final Activity activity = getActivity();
361         if (activity != null) {
362             activity.invalidateOptionsMenu();
363         }
364     }
365 
cancelSyncForEnabledProviders()366     private void cancelSyncForEnabledProviders() {
367         requestOrCancelSyncForEnabledProviders(false /* cancel them */);
368         final Activity activity = getActivity();
369         if (activity != null) {
370             activity.invalidateOptionsMenu();
371         }
372     }
373 
requestOrCancelSyncForEnabledProviders(boolean startSync)374     private void requestOrCancelSyncForEnabledProviders(boolean startSync) {
375         // sync everything that the user has enabled
376         int count = getPreferenceScreen().getPreferenceCount();
377         for (int i = 0; i < count; i++) {
378             Preference pref = getPreferenceScreen().getPreference(i);
379             if (!(pref instanceof SyncStateSwitchPreference)) {
380                 continue;
381             }
382             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) pref;
383             if (!syncPref.isChecked()) {
384                 continue;
385             }
386             requestOrCancelSync(syncPref.getAccount(), syncPref.getAuthority(), startSync);
387         }
388         // plus whatever the system needs to sync, e.g., invisible sync adapters
389         if (mAccount != null) {
390             for (SyncAdapterType syncAdapter : mInvisibleAdapters) {
391                 requestOrCancelSync(mAccount, syncAdapter.authority, startSync);
392             }
393         }
394     }
395 
requestOrCancelSync(Account account, String authority, boolean flag)396     private void requestOrCancelSync(Account account, String authority, boolean flag) {
397         if (flag) {
398             Bundle extras = new Bundle();
399             extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
400             ContentResolver.requestSyncAsUser(account, authority, mUserHandle.getIdentifier(),
401                     extras);
402         } else {
403             ContentResolver.cancelSyncAsUser(account, authority, mUserHandle.getIdentifier());
404         }
405     }
406 
isSyncing(List<SyncInfo> currentSyncs, Account account, String authority)407     private boolean isSyncing(List<SyncInfo> currentSyncs, Account account, String authority) {
408         for (SyncInfo syncInfo : currentSyncs) {
409             if (syncInfo.account.equals(account) && syncInfo.authority.equals(authority)) {
410                 return true;
411             }
412         }
413         return false;
414     }
415 
416     @Override
onSyncStateUpdated()417     protected void onSyncStateUpdated() {
418         if (!isResumed()) return;
419         setFeedsState();
420         final Activity activity = getActivity();
421         if (activity != null) {
422             activity.invalidateOptionsMenu();
423         }
424     }
425 
setFeedsState()426     private void setFeedsState() {
427         // iterate over all the preferences, setting the state properly for each
428         Date date = new Date();
429         final int userId = mUserHandle.getIdentifier();
430         List<SyncInfo> currentSyncs = ContentResolver.getCurrentSyncsAsUser(userId);
431         boolean syncIsFailing = false;
432 
433         // Refresh the sync status switches - some syncs may have become active.
434         updateAccountSwitches();
435 
436         for (int i = 0, count = getPreferenceScreen().getPreferenceCount(); i < count; i++) {
437             Preference pref = getPreferenceScreen().getPreference(i);
438             if (!(pref instanceof SyncStateSwitchPreference)) {
439                 continue;
440             }
441             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) pref;
442 
443             String authority = syncPref.getAuthority();
444             Account account = syncPref.getAccount();
445 
446             SyncStatusInfo status = ContentResolver.getSyncStatusAsUser(account, authority, userId);
447             boolean syncEnabled = ContentResolver.getSyncAutomaticallyAsUser(account, authority,
448                     userId);
449             boolean authorityIsPending = status == null ? false : status.pending;
450             boolean initialSync = status == null ? false : status.initialize;
451 
452             boolean activelySyncing = isSyncing(currentSyncs, account, authority);
453             boolean lastSyncFailed = status != null
454                     && status.lastFailureTime != 0
455                     && status.getLastFailureMesgAsInt(0)
456                     != ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
457             if (!syncEnabled) lastSyncFailed = false;
458             if (lastSyncFailed && !activelySyncing && !authorityIsPending) {
459                 syncIsFailing = true;
460             }
461             if (Log.isLoggable(TAG, Log.DEBUG)) {
462                 Log.d(TAG, "Update sync status: " + account + " " + authority +
463                         " active = " + activelySyncing + " pend =" + authorityIsPending);
464             }
465 
466             final long successEndTime = (status == null) ? 0 : status.lastSuccessTime;
467             if (!syncEnabled) {
468                 syncPref.setSummary(R.string.sync_disabled);
469             } else if (activelySyncing) {
470                 syncPref.setSummary(R.string.sync_in_progress);
471             } else if (successEndTime != 0) {
472                 date.setTime(successEndTime);
473                 final String timeString = formatSyncDate(getContext(), date);
474                 syncPref.setSummary(getResources().getString(R.string.last_synced, timeString));
475             } else {
476                 syncPref.setSummary("");
477             }
478             int syncState = ContentResolver.getIsSyncableAsUser(account, authority, userId);
479 
480             syncPref.setActive(activelySyncing && (syncState >= 0) &&
481                     !initialSync);
482             syncPref.setPending(authorityIsPending && (syncState >= 0) &&
483                     !initialSync);
484 
485             syncPref.setFailed(lastSyncFailed);
486             final boolean oneTimeSyncMode = !ContentResolver.getMasterSyncAutomaticallyAsUser(
487                     userId);
488             syncPref.setOneTimeSyncMode(oneTimeSyncMode);
489             syncPref.setChecked(oneTimeSyncMode || syncEnabled);
490         }
491         if (syncIsFailing) {
492             getPreferenceScreen().addPreference(new FooterPreference.Builder(
493                     getActivity()).setTitle(R.string.sync_is_failing).build());
494         }
495     }
496 
497     @Override
onAccountsUpdate(final UserHandle userHandle)498     public void onAccountsUpdate(final UserHandle userHandle) {
499         super.onAccountsUpdate(userHandle);
500         if (!accountExists(mAccount)) {
501             // The account was deleted
502             finish();
503             return;
504         }
505         updateAccountSwitches();
506         onSyncStateUpdated();
507     }
508 
accountExists(Account account)509     private boolean accountExists(Account account) {
510         if (account == null) return false;
511 
512         Account[] accounts = AccountManager.get(getActivity()).getAccountsByTypeAsUser(
513                 account.type, mUserHandle);
514         final int count = accounts.length;
515         for (int i = 0; i < count; i++) {
516             if (accounts[i].equals(account)) {
517                 return true;
518             }
519         }
520         return false;
521     }
522 
updateAccountSwitches()523     private void updateAccountSwitches() {
524         mInvisibleAdapters.clear();
525 
526         SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
527                 mUserHandle.getIdentifier());
528         ArrayList<SyncAdapterType> authorities = new ArrayList<>();
529         for (int i = 0, n = syncAdapters.length; i < n; i++) {
530             final SyncAdapterType sa = syncAdapters[i];
531             // Only keep track of sync adapters for this account
532             if (!sa.accountType.equals(mAccount.type)) continue;
533             if (sa.isUserVisible()) {
534                 if (Log.isLoggable(TAG, Log.DEBUG)) {
535                     Log.d(TAG, "updateAccountSwitches: added authority " + sa.authority
536                             + " to accountType " + sa.accountType);
537                 }
538                 authorities.add(sa);
539             } else {
540                 // keep track of invisible sync adapters, so sync now forces
541                 // them to sync as well.
542                 mInvisibleAdapters.add(sa);
543             }
544         }
545 
546         if (Log.isLoggable(TAG, Log.DEBUG)) {
547             Log.d(TAG, "looking for sync adapters that match account " + mAccount);
548         }
549 
550         cacheRemoveAllPrefs(getPreferenceScreen());
551         getCachedPreference(EntityHeaderController.PREF_KEY_APP_HEADER);
552         for (int j = 0, m = authorities.size(); j < m; j++) {
553             final SyncAdapterType syncAdapter = authorities.get(j);
554             // We could check services here....
555             int syncState = ContentResolver.getIsSyncableAsUser(mAccount, syncAdapter.authority,
556                     mUserHandle.getIdentifier());
557             if (Log.isLoggable(TAG, Log.DEBUG)) {
558                 Log.d(TAG, "  found authority " + syncAdapter.authority + " " + syncState);
559             }
560             if (syncState > 0) {
561                 final int uid;
562                 try {
563                     uid = getContext().getPackageManager().getPackageUidAsUser(
564                             syncAdapter.getPackageName(), mUserHandle.getIdentifier());
565                     addSyncStateSwitch(mAccount, syncAdapter.authority,
566                             syncAdapter.getPackageName(), uid);
567                 } catch (PackageManager.NameNotFoundException e) {
568                     Log.e(TAG, "No uid for package" + syncAdapter.getPackageName(), e);
569                 }
570             }
571         }
572         removeCachedPrefs(getPreferenceScreen());
573     }
574 
575     @Override
getHelpResource()576     public int getHelpResource() {
577         return R.string.help_url_accounts;
578     }
579 
580     @VisibleForTesting
enabledSyncNowMenu()581     boolean enabledSyncNowMenu() {
582         boolean enabled = false;
583         for (int i = 0, count = getPreferenceScreen().getPreferenceCount(); i < count; i++) {
584             final Preference pref = getPreferenceScreen().getPreference(i);
585             if (!(pref instanceof SyncStateSwitchPreference)) {
586                 continue;
587             }
588             final SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) pref;
589             if (syncPref.isChecked()) {
590                 enabled = true;
591                 break;
592             }
593         }
594         return enabled;
595     }
596 
formatSyncDate(Context context, Date date)597     private static String formatSyncDate(Context context, Date date) {
598         return DateUtils.formatDateTime(context, date.getTime(),
599                 DateUtils.FORMAT_SHOW_DATE
600                         | DateUtils.FORMAT_SHOW_YEAR
601                         | DateUtils.FORMAT_SHOW_TIME);
602     }
603 
addUidAndGenerateRequestCode(int uid)604     private int addUidAndGenerateRequestCode(int uid) {
605         if (mUidRequestCodeMap.containsKey(uid)) {
606             return mUidRequestCodeMap.get(uid);
607         }
608         final int requestCode = mUidRequestCodeMap.size() + 1;
609         mUidRequestCodeMap.put(uid, requestCode);
610         return requestCode;
611     }
612 
getRequestCodeByUid(int uid)613     private int getRequestCodeByUid(int uid) {
614         if (!mUidRequestCodeMap.containsKey(uid)) {
615             return -1;
616         }
617         return mUidRequestCodeMap.get(uid);
618     }
619 }
620