Home | History | Annotate | Download | only in accounts
      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 android.accounts.Account;
     20 import android.accounts.AccountManager;
     21 import android.accounts.AccountManagerCallback;
     22 import android.accounts.AccountManagerFuture;
     23 import android.accounts.AuthenticatorException;
     24 import android.accounts.OperationCanceledException;
     25 import android.app.Activity;
     26 import android.app.AlertDialog;
     27 import android.app.Dialog;
     28 import android.content.ContentResolver;
     29 import android.content.Context;
     30 import android.content.DialogInterface;
     31 import android.content.SyncAdapterType;
     32 import android.content.SyncInfo;
     33 import android.content.SyncStatusInfo;
     34 import android.content.pm.ProviderInfo;
     35 import android.content.pm.UserInfo;
     36 import android.os.Binder;
     37 import android.os.Bundle;
     38 import android.os.UserHandle;
     39 import android.os.UserManager;
     40 import android.support.v7.preference.Preference;
     41 import android.text.TextUtils;
     42 import android.util.Log;
     43 import android.view.LayoutInflater;
     44 import android.view.Menu;
     45 import android.view.MenuInflater;
     46 import android.view.MenuItem;
     47 import android.view.View;
     48 import android.view.ViewGroup;
     49 import android.widget.ImageView;
     50 import android.widget.TextView;
     51 
     52 import com.google.android.collect.Lists;
     53 
     54 import com.android.internal.logging.MetricsProto.MetricsEvent;
     55 import com.android.settings.R;
     56 import com.android.settings.Utils;
     57 import com.android.settingslib.RestrictedLockUtils;
     58 
     59 import java.io.IOException;
     60 import java.util.ArrayList;
     61 import java.util.Collections;
     62 import java.util.Date;
     63 import java.util.List;
     64 
     65 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
     66 
     67 public class AccountSyncSettings extends AccountPreferenceBase {
     68 
     69     public static final String ACCOUNT_KEY = "account";
     70     private static final int MENU_SYNC_NOW_ID       = Menu.FIRST;
     71     private static final int MENU_SYNC_CANCEL_ID    = Menu.FIRST + 1;
     72     private static final int MENU_REMOVE_ACCOUNT_ID = Menu.FIRST + 2;
     73     private static final int REALLY_REMOVE_DIALOG = 100;
     74     private static final int FAILED_REMOVAL_DIALOG = 101;
     75     private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;
     76     private TextView mUserId;
     77     private TextView mProviderId;
     78     private ImageView mProviderIcon;
     79     private TextView mErrorInfoView;
     80     private Account mAccount;
     81     private ArrayList<SyncStateSwitchPreference> mSwitches =
     82                 new ArrayList<SyncStateSwitchPreference>();
     83     private ArrayList<SyncAdapterType> mInvisibleAdapters = Lists.newArrayList();
     84 
     85     @Override
     86     public Dialog onCreateDialog(final int id) {
     87         Dialog dialog = null;
     88         if (id == REALLY_REMOVE_DIALOG) {
     89             dialog = new AlertDialog.Builder(getActivity())
     90                 .setTitle(R.string.really_remove_account_title)
     91                 .setMessage(R.string.really_remove_account_message)
     92                 .setNegativeButton(android.R.string.cancel, null)
     93                 .setPositiveButton(R.string.remove_account_label,
     94                         new DialogInterface.OnClickListener() {
     95                     @Override
     96                     public void onClick(DialogInterface dialog, int which) {
     97                         Activity activity = getActivity();
     98                         AccountManager.get(activity)
     99                                 .removeAccountAsUser(mAccount, activity,
    100                                 new AccountManagerCallback<Bundle>() {
    101                             @Override
    102                             public void run(AccountManagerFuture<Bundle> future) {
    103                                 // If already out of this screen, don't proceed.
    104                                 if (!AccountSyncSettings.this.isResumed()) {
    105                                     return;
    106                                 }
    107                                 boolean failed = true;
    108                                 try {
    109                                     if (future.getResult()
    110                                             .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    111                                         failed = false;
    112                                     }
    113                                 } catch (OperationCanceledException e) {
    114                                     // handled below
    115                                 } catch (IOException e) {
    116                                     // handled below
    117                                 } catch (AuthenticatorException e) {
    118                                     // handled below
    119                                 }
    120                                 if (failed && getActivity() != null &&
    121                                         !getActivity().isFinishing()) {
    122                                     showDialog(FAILED_REMOVAL_DIALOG);
    123                                 } else {
    124                                     finish();
    125                                 }
    126                             }
    127                         }, null, mUserHandle);
    128                     }
    129                 })
    130                 .create();
    131         } else if (id == FAILED_REMOVAL_DIALOG) {
    132             dialog = new AlertDialog.Builder(getActivity())
    133                 .setTitle(R.string.really_remove_account_title)
    134                 .setPositiveButton(android.R.string.ok, null)
    135                 .setMessage(R.string.remove_account_failed)
    136                 .create();
    137         } else if (id == CANT_DO_ONETIME_SYNC_DIALOG) {
    138             dialog = new AlertDialog.Builder(getActivity())
    139                 .setTitle(R.string.cant_sync_dialog_title)
    140                 .setMessage(R.string.cant_sync_dialog_message)
    141                 .setPositiveButton(android.R.string.ok, null)
    142                 .create();
    143         }
    144         return dialog;
    145     }
    146 
    147     @Override
    148     protected int getMetricsCategory() {
    149         return MetricsEvent.ACCOUNTS_ACCOUNT_SYNC;
    150     }
    151 
    152     @Override
    153     public void onCreate(Bundle icicle) {
    154         super.onCreate(icicle);
    155         setPreferenceScreen(null);
    156         addPreferencesFromResource(R.xml.account_sync_settings);
    157         getPreferenceScreen().setOrderingAsAdded(false);
    158         setAccessibilityTitle();
    159 
    160         setHasOptionsMenu(true);
    161     }
    162 
    163     @Override
    164     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    165             Bundle savedInstanceState) {
    166         final View view = inflater.inflate(R.layout.account_sync_screen, container, false);
    167 
    168         final ViewGroup prefs_container = (ViewGroup) view.findViewById(R.id.prefs_container);
    169         Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
    170         View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
    171         prefs_container.addView(prefs);
    172 
    173         initializeUi(view);
    174 
    175         return view;
    176     }
    177 
    178     protected void initializeUi(final View rootView) {
    179         mErrorInfoView = (TextView) rootView.findViewById(R.id.sync_settings_error_info);
    180         mErrorInfoView.setVisibility(View.GONE);
    181 
    182         mUserId = (TextView) rootView.findViewById(R.id.user_id);
    183         mProviderId = (TextView) rootView.findViewById(R.id.provider_id);
    184         mProviderIcon = (ImageView) rootView.findViewById(R.id.provider_icon);
    185     }
    186 
    187     @Override
    188     public void onActivityCreated(Bundle savedInstanceState) {
    189         super.onActivityCreated(savedInstanceState);
    190 
    191         Bundle arguments = getArguments();
    192         if (arguments == null) {
    193             Log.e(TAG, "No arguments provided when starting intent. ACCOUNT_KEY needed.");
    194             finish();
    195             return;
    196         }
    197         mAccount = (Account) arguments.getParcelable(ACCOUNT_KEY);
    198         if (!accountExists(mAccount)) {
    199             Log.e(TAG, "Account provided does not exist: " + mAccount);
    200             finish();
    201             return;
    202         }
    203         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    204           Log.v(TAG, "Got account: " + mAccount);
    205         }
    206         mUserId.setText(mAccount.name);
    207         mProviderId.setText(mAccount.type);
    208     }
    209 
    210     private void setAccessibilityTitle() {
    211         final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
    212         UserInfo user = um.getUserInfo(mUserHandle.getIdentifier());
    213         boolean isWorkProfile = user != null ? user.isManagedProfile() : false;
    214         CharSequence currentTitle = getActivity().getTitle();
    215         String accessibilityTitle =
    216                 getString(isWorkProfile
    217                         ? R.string.accessibility_work_account_title
    218                         : R.string.accessibility_personal_account_title, currentTitle);
    219         getActivity().setTitle(Utils.createAccessibleSequence(currentTitle, accessibilityTitle));
    220     }
    221 
    222     @Override
    223     public void onResume() {
    224         removePreference("dummy");
    225         mAuthenticatorHelper.listenToAccountUpdates();
    226         updateAuthDescriptions();
    227         onAccountsUpdate(Binder.getCallingUserHandle());
    228         super.onResume();
    229     }
    230 
    231     @Override
    232     public void onPause() {
    233         super.onPause();
    234         mAuthenticatorHelper.stopListeningToAccountUpdates();
    235     }
    236 
    237     private void addSyncStateSwitch(Account account, String authority) {
    238         SyncStateSwitchPreference item = (SyncStateSwitchPreference) getCachedPreference(authority);
    239         if (item == null) {
    240             item = new SyncStateSwitchPreference(getPrefContext(), account, authority);
    241             getPreferenceScreen().addPreference(item);
    242         } else {
    243             item.setup(account, authority);
    244         }
    245         item.setPersistent(false);
    246         final ProviderInfo providerInfo = getPackageManager().resolveContentProviderAsUser(
    247                 authority, 0, mUserHandle.getIdentifier());
    248         if (providerInfo == null) {
    249             return;
    250         }
    251         CharSequence providerLabel = providerInfo.loadLabel(getPackageManager());
    252         if (TextUtils.isEmpty(providerLabel)) {
    253             Log.e(TAG, "Provider needs a label for authority '" + authority + "'");
    254             return;
    255         }
    256         String title = getString(R.string.sync_item_title, providerLabel);
    257         item.setTitle(title);
    258         item.setKey(authority);
    259     }
    260 
    261     @Override
    262     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    263 
    264         MenuItem syncNow = menu.add(0, MENU_SYNC_NOW_ID, 0,
    265                 getString(R.string.sync_menu_sync_now))
    266                 .setIcon(R.drawable.ic_menu_refresh_holo_dark);
    267         MenuItem syncCancel = menu.add(0, MENU_SYNC_CANCEL_ID, 0,
    268                 getString(R.string.sync_menu_sync_cancel))
    269                 .setIcon(com.android.internal.R.drawable.ic_menu_close_clear_cancel);
    270 
    271         MenuItem removeAccount = menu.add(0, MENU_REMOVE_ACCOUNT_ID, 0,
    272                 getString(R.string.remove_account_label))
    273                 .setIcon(R.drawable.ic_menu_delete);
    274         removeAccount.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER |
    275                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    276         if (RestrictedLockUtils.hasBaseUserRestriction(getPrefContext(),
    277                 UserManager.DISALLOW_MODIFY_ACCOUNTS, mUserHandle.getIdentifier())) {
    278             removeAccount.setEnabled(false);
    279         } else {
    280             EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(
    281                     getPrefContext(), UserManager.DISALLOW_MODIFY_ACCOUNTS,
    282                     mUserHandle.getIdentifier());
    283             if (admin == null) {
    284                 admin = RestrictedLockUtils.checkIfAccountManagementDisabled(
    285                         getPrefContext(), mAccount.type, mUserHandle.getIdentifier());
    286             }
    287             RestrictedLockUtils.setMenuItemAsDisabledByAdmin(getPrefContext(),
    288                     removeAccount, admin);
    289         }
    290 
    291         syncNow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER |
    292                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    293         syncCancel.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER |
    294                 MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    295 
    296         super.onCreateOptionsMenu(menu, inflater);
    297     }
    298 
    299     @Override
    300     public void onPrepareOptionsMenu(Menu menu) {
    301         super.onPrepareOptionsMenu(menu);
    302         // Note that this also counts accounts that are not currently displayed
    303         boolean syncActive = !ContentResolver.getCurrentSyncsAsUser(
    304                 mUserHandle.getIdentifier()).isEmpty();
    305         menu.findItem(MENU_SYNC_NOW_ID).setVisible(!syncActive);
    306         menu.findItem(MENU_SYNC_CANCEL_ID).setVisible(syncActive);
    307     }
    308 
    309     @Override
    310     public boolean onOptionsItemSelected(MenuItem item) {
    311         switch (item.getItemId()) {
    312             case MENU_SYNC_NOW_ID:
    313                 startSyncForEnabledProviders();
    314                 return true;
    315             case MENU_SYNC_CANCEL_ID:
    316                 cancelSyncForEnabledProviders();
    317                 return true;
    318             case MENU_REMOVE_ACCOUNT_ID:
    319                 showDialog(REALLY_REMOVE_DIALOG);
    320                 return true;
    321         }
    322         return super.onOptionsItemSelected(item);
    323     }
    324 
    325     @Override
    326     public boolean onPreferenceTreeClick(Preference preference) {
    327         if (preference instanceof SyncStateSwitchPreference) {
    328             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
    329             String authority = syncPref.getAuthority();
    330             Account account = syncPref.getAccount();
    331             final int userId = mUserHandle.getIdentifier();
    332             boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
    333                     authority, userId);
    334             if (syncPref.isOneTimeSyncMode()) {
    335                 requestOrCancelSync(account, authority, true);
    336             } else {
    337                 boolean syncOn = syncPref.isChecked();
    338                 boolean oldSyncState = syncAutomatically;
    339                 if (syncOn != oldSyncState) {
    340                     // if we're enabling sync, this will request a sync as well
    341                     ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
    342                     // if the master sync switch is off, the request above will
    343                     // get dropped.  when the user clicks on this toggle,
    344                     // we want to force the sync, however.
    345                     if (!ContentResolver.getMasterSyncAutomaticallyAsUser(userId) || !syncOn) {
    346                         requestOrCancelSync(account, authority, syncOn);
    347                     }
    348                 }
    349             }
    350             return true;
    351         } else {
    352             return super.onPreferenceTreeClick(preference);
    353         }
    354     }
    355 
    356     private void startSyncForEnabledProviders() {
    357         requestOrCancelSyncForEnabledProviders(true /* start them */);
    358         final Activity activity = getActivity();
    359         if (activity != null) {
    360             activity.invalidateOptionsMenu();
    361         }
    362     }
    363 
    364     private void cancelSyncForEnabledProviders() {
    365         requestOrCancelSyncForEnabledProviders(false /* cancel them */);
    366         final Activity activity = getActivity();
    367         if (activity != null) {
    368             activity.invalidateOptionsMenu();
    369         }
    370     }
    371 
    372     private void requestOrCancelSyncForEnabledProviders(boolean startSync) {
    373         // sync everything that the user has enabled
    374         int count = getPreferenceScreen().getPreferenceCount();
    375         for (int i = 0; i < count; i++) {
    376             Preference pref = getPreferenceScreen().getPreference(i);
    377             if (! (pref instanceof SyncStateSwitchPreference)) {
    378                 continue;
    379             }
    380             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) pref;
    381             if (!syncPref.isChecked()) {
    382                 continue;
    383             }
    384             requestOrCancelSync(syncPref.getAccount(), syncPref.getAuthority(), startSync);
    385         }
    386         // plus whatever the system needs to sync, e.g., invisible sync adapters
    387         if (mAccount != null) {
    388             for (SyncAdapterType syncAdapter : mInvisibleAdapters) {
    389                   requestOrCancelSync(mAccount, syncAdapter.authority, startSync);
    390             }
    391         }
    392     }
    393 
    394     private void requestOrCancelSync(Account account, String authority, boolean flag) {
    395         if (flag) {
    396             Bundle extras = new Bundle();
    397             extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    398             ContentResolver.requestSyncAsUser(account, authority, mUserHandle.getIdentifier(),
    399                     extras);
    400         } else {
    401             ContentResolver.cancelSyncAsUser(account, authority, mUserHandle.getIdentifier());
    402         }
    403     }
    404 
    405     private boolean isSyncing(List<SyncInfo> currentSyncs, Account account, String authority) {
    406         for (SyncInfo syncInfo : currentSyncs) {
    407             if (syncInfo.account.equals(account) && syncInfo.authority.equals(authority)) {
    408                 return true;
    409             }
    410         }
    411         return false;
    412     }
    413 
    414     @Override
    415     protected void onSyncStateUpdated() {
    416         if (!isResumed()) return;
    417         setFeedsState();
    418         final Activity activity = getActivity();
    419         if (activity != null) {
    420             activity.invalidateOptionsMenu();
    421         }
    422     }
    423 
    424     private void setFeedsState() {
    425         // iterate over all the preferences, setting the state properly for each
    426         Date date = new Date();
    427         final int userId = mUserHandle.getIdentifier();
    428         List<SyncInfo> currentSyncs = ContentResolver.getCurrentSyncsAsUser(userId);
    429         boolean syncIsFailing = false;
    430 
    431         // Refresh the sync status switches - some syncs may have become active.
    432         updateAccountSwitches();
    433 
    434         for (int i = 0, count = getPreferenceScreen().getPreferenceCount(); i < count; i++) {
    435             Preference pref = getPreferenceScreen().getPreference(i);
    436             if (! (pref instanceof SyncStateSwitchPreference)) {
    437                 continue;
    438             }
    439             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) pref;
    440 
    441             String authority = syncPref.getAuthority();
    442             Account account = syncPref.getAccount();
    443 
    444             SyncStatusInfo status = ContentResolver.getSyncStatusAsUser(account, authority, userId);
    445             boolean syncEnabled = ContentResolver.getSyncAutomaticallyAsUser(account, authority,
    446                     userId);
    447             boolean authorityIsPending = status == null ? false : status.pending;
    448             boolean initialSync = status == null ? false : status.initialize;
    449 
    450             boolean activelySyncing = isSyncing(currentSyncs, account, authority);
    451             boolean lastSyncFailed = status != null
    452                     && status.lastFailureTime != 0
    453                     && status.getLastFailureMesgAsInt(0)
    454                        != ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
    455             if (!syncEnabled) lastSyncFailed = false;
    456             if (lastSyncFailed && !activelySyncing && !authorityIsPending) {
    457                 syncIsFailing = true;
    458             }
    459             if (Log.isLoggable(TAG, Log.VERBOSE)) {
    460                 Log.d(TAG, "Update sync status: " + account + " " + authority +
    461                         " active = " + activelySyncing + " pend =" +  authorityIsPending);
    462             }
    463 
    464             final long successEndTime = (status == null) ? 0 : status.lastSuccessTime;
    465             if (!syncEnabled) {
    466                 syncPref.setSummary(R.string.sync_disabled);
    467             } else if (activelySyncing) {
    468                 syncPref.setSummary(R.string.sync_in_progress);
    469             } else if (successEndTime != 0) {
    470                 date.setTime(successEndTime);
    471                 final String timeString = formatSyncDate(date);
    472                 syncPref.setSummary(getResources().getString(R.string.last_synced, timeString));
    473             } else {
    474                 syncPref.setSummary("");
    475             }
    476             int syncState = ContentResolver.getIsSyncableAsUser(account, authority, userId);
    477 
    478             syncPref.setActive(activelySyncing && (syncState >= 0) &&
    479                     !initialSync);
    480             syncPref.setPending(authorityIsPending && (syncState >= 0) &&
    481                     !initialSync);
    482 
    483             syncPref.setFailed(lastSyncFailed);
    484             final boolean oneTimeSyncMode = !ContentResolver.getMasterSyncAutomaticallyAsUser(
    485                 userId);
    486             syncPref.setOneTimeSyncMode(oneTimeSyncMode);
    487             syncPref.setChecked(oneTimeSyncMode || syncEnabled);
    488         }
    489         mErrorInfoView.setVisibility(syncIsFailing ? View.VISIBLE : View.GONE);
    490     }
    491 
    492     @Override
    493     public void onAccountsUpdate(final UserHandle userHandle) {
    494         super.onAccountsUpdate(userHandle);
    495         if (!accountExists(mAccount)) {
    496             // The account was deleted
    497             finish();
    498             return;
    499         }
    500         updateAccountSwitches();
    501         onSyncStateUpdated();
    502     }
    503 
    504     private boolean accountExists(Account account) {
    505         if (account == null) return false;
    506 
    507         Account[] accounts = AccountManager.get(getActivity()).getAccountsByTypeAsUser(
    508                 account.type, mUserHandle);
    509         final int count = accounts.length;
    510         for (int i = 0; i < count; i++) {
    511             if (accounts[i].equals(account)) {
    512                 return true;
    513             }
    514         }
    515         return false;
    516     }
    517 
    518     private void updateAccountSwitches() {
    519         mInvisibleAdapters.clear();
    520 
    521         SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
    522                 mUserHandle.getIdentifier());
    523         ArrayList<String> authorities = new ArrayList<String>();
    524         for (int i = 0, n = syncAdapters.length; i < n; i++) {
    525             final SyncAdapterType sa = syncAdapters[i];
    526             // Only keep track of sync adapters for this account
    527             if (!sa.accountType.equals(mAccount.type)) continue;
    528             if (sa.isUserVisible()) {
    529                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
    530                     Log.d(TAG, "updateAccountSwitches: added authority " + sa.authority
    531                             + " to accountType " + sa.accountType);
    532                 }
    533                 authorities.add(sa.authority);
    534             } else {
    535                 // keep track of invisible sync adapters, so sync now forces
    536                 // them to sync as well.
    537                 mInvisibleAdapters.add(sa);
    538             }
    539         }
    540 
    541         if (Log.isLoggable(TAG, Log.VERBOSE)) {
    542             Log.d(TAG, "looking for sync adapters that match account " + mAccount);
    543         }
    544         cacheRemoveAllPrefs(getPreferenceScreen());
    545         for (int j = 0, m = authorities.size(); j < m; j++) {
    546             final String authority = authorities.get(j);
    547             // We could check services here....
    548             int syncState = ContentResolver.getIsSyncableAsUser(mAccount, authority,
    549                     mUserHandle.getIdentifier());
    550             if (Log.isLoggable(TAG, Log.VERBOSE)) {
    551                 Log.d(TAG, "  found authority " + authority + " " + syncState);
    552             }
    553             if (syncState > 0) {
    554                 addSyncStateSwitch(mAccount, authority);
    555             }
    556         }
    557         removeCachedPrefs(getPreferenceScreen());
    558     }
    559 
    560     /**
    561      * Updates the titlebar with an icon for the provider type.
    562      */
    563     @Override
    564     protected void onAuthDescriptionsUpdated() {
    565         super.onAuthDescriptionsUpdated();
    566         if (mAccount != null) {
    567             mProviderIcon.setImageDrawable(getDrawableForType(mAccount.type));
    568             mProviderId.setText(getLabelForType(mAccount.type));
    569         }
    570     }
    571 
    572     @Override
    573     protected int getHelpResource() {
    574         return R.string.help_url_accounts;
    575     }
    576 }
    577