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.OnAccountsUpdateListener;
     22 import android.app.ActionBar;
     23 import android.app.Activity;
     24 import android.app.ActivityManager;
     25 import android.app.ActivityManagerNative;
     26 import android.content.ContentResolver;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.SyncAdapterType;
     30 import android.content.SyncInfo;
     31 import android.content.SyncStatusInfo;
     32 import android.content.pm.PackageManager;
     33 import android.content.pm.ResolveInfo;
     34 import android.graphics.drawable.Drawable;
     35 import android.os.Bundle;
     36 import android.preference.Preference;
     37 import android.preference.PreferenceActivity;
     38 import android.preference.PreferenceScreen;
     39 import android.text.format.DateFormat;
     40 import android.util.Log;
     41 import android.view.Gravity;
     42 import android.view.LayoutInflater;
     43 import android.view.Menu;
     44 import android.view.MenuInflater;
     45 import android.view.MenuItem;
     46 import android.view.View;
     47 import android.view.ViewGroup;
     48 import android.widget.CompoundButton;
     49 import android.widget.Switch;
     50 import android.widget.TextView;
     51 
     52 import com.android.settings.AccountPreference;
     53 import com.android.settings.R;
     54 import com.android.settings.Settings;
     55 
     56 import java.util.ArrayList;
     57 import java.util.Date;
     58 import java.util.HashSet;
     59 
     60 public class ManageAccountsSettings extends AccountPreferenceBase
     61         implements OnAccountsUpdateListener {
     62 
     63     private static final String ACCOUNT_KEY = "account"; // to pass to auth settings
     64     public static final String KEY_ACCOUNT_TYPE = "account_type";
     65     public static final String KEY_ACCOUNT_LABEL = "account_label";
     66 
     67     private static final int MENU_SYNC_NOW_ID = Menu.FIRST;
     68     private static final int MENU_SYNC_CANCEL_ID    = Menu.FIRST + 1;
     69 
     70     private static final int REQUEST_SHOW_SYNC_SETTINGS = 1;
     71 
     72     private String[] mAuthorities;
     73     private TextView mErrorInfoView;
     74 
     75     private SettingsDialogFragment mDialogFragment;
     76     // If an account type is set, then show only accounts of that type
     77     private String mAccountType;
     78     // Temporary hack, to deal with backward compatibility
     79     private Account mFirstAccount;
     80 
     81     @Override
     82     public void onCreate(Bundle icicle) {
     83         super.onCreate(icicle);
     84 
     85         Bundle args = getArguments();
     86         if (args != null && args.containsKey(KEY_ACCOUNT_TYPE)) {
     87             mAccountType = args.getString(KEY_ACCOUNT_TYPE);
     88         }
     89         addPreferencesFromResource(R.xml.manage_accounts_settings);
     90         setHasOptionsMenu(true);
     91     }
     92 
     93     @Override
     94     public void onStart() {
     95         super.onStart();
     96         Activity activity = getActivity();
     97         AccountManager.get(activity).addOnAccountsUpdatedListener(this, null, true);
     98     }
     99 
    100     @Override
    101     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    102             Bundle savedInstanceState) {
    103         final View view = inflater.inflate(R.layout.manage_accounts_screen, container, false);
    104         return view;
    105     }
    106 
    107     @Override
    108     public void onActivityCreated(Bundle savedInstanceState) {
    109         super.onActivityCreated(savedInstanceState);
    110 
    111         final Activity activity = getActivity();
    112         final View view = getView();
    113 
    114         mErrorInfoView = (TextView)view.findViewById(R.id.sync_settings_error_info);
    115         mErrorInfoView.setVisibility(View.GONE);
    116 
    117         mAuthorities = activity.getIntent().getStringArrayExtra(AUTHORITIES_FILTER_KEY);
    118 
    119         Bundle args = getArguments();
    120         if (args != null && args.containsKey(KEY_ACCOUNT_LABEL)) {
    121             getActivity().setTitle(args.getString(KEY_ACCOUNT_LABEL));
    122         }
    123         updateAuthDescriptions();
    124     }
    125 
    126     @Override
    127     public void onStop() {
    128         super.onStop();
    129         final Activity activity = getActivity();
    130         AccountManager.get(activity).removeOnAccountsUpdatedListener(this);
    131         activity.getActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_CUSTOM);
    132         activity.getActionBar().setCustomView(null);
    133     }
    134 
    135     @Override
    136     public boolean onPreferenceTreeClick(PreferenceScreen preferences, Preference preference) {
    137         if (preference instanceof AccountPreference) {
    138             startAccountSettings((AccountPreference) preference);
    139         } else {
    140             return false;
    141         }
    142         return true;
    143     }
    144 
    145     private void startAccountSettings(AccountPreference acctPref) {
    146         Bundle args = new Bundle();
    147         args.putParcelable(AccountSyncSettings.ACCOUNT_KEY, acctPref.getAccount());
    148         ((PreferenceActivity) getActivity()).startPreferencePanel(
    149                 AccountSyncSettings.class.getCanonicalName(), args,
    150                 R.string.account_sync_settings_title, acctPref.getAccount().name,
    151                 this, REQUEST_SHOW_SYNC_SETTINGS);
    152     }
    153 
    154     @Override
    155     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    156         MenuItem syncNow = menu.add(0, MENU_SYNC_NOW_ID, 0,
    157                 getString(R.string.sync_menu_sync_now))
    158                 .setIcon(R.drawable.ic_menu_refresh_holo_dark);
    159         MenuItem syncCancel = menu.add(0, MENU_SYNC_CANCEL_ID, 0,
    160                 getString(R.string.sync_menu_sync_cancel))
    161                 .setIcon(com.android.internal.R.drawable.ic_menu_close_clear_cancel);
    162         super.onCreateOptionsMenu(menu, inflater);
    163     }
    164 
    165     @Override
    166     public void onPrepareOptionsMenu(Menu menu) {
    167         super.onPrepareOptionsMenu(menu);
    168         boolean syncActive = ContentResolver.getCurrentSync() != null;
    169         menu.findItem(MENU_SYNC_NOW_ID).setVisible(!syncActive && mFirstAccount != null);
    170         menu.findItem(MENU_SYNC_CANCEL_ID).setVisible(syncActive && mFirstAccount != null);
    171     }
    172 
    173     @Override
    174     public boolean onOptionsItemSelected(MenuItem item) {
    175         switch (item.getItemId()) {
    176         case MENU_SYNC_NOW_ID:
    177             requestOrCancelSyncForAccounts(true);
    178             return true;
    179         case MENU_SYNC_CANCEL_ID:
    180             requestOrCancelSyncForAccounts(false);
    181             return true;
    182         }
    183         return super.onOptionsItemSelected(item);
    184     }
    185 
    186     private void requestOrCancelSyncForAccounts(boolean sync) {
    187         SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes();
    188         Bundle extras = new Bundle();
    189         extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    190         int count = getPreferenceScreen().getPreferenceCount();
    191         // For each account
    192         for (int i = 0; i < count; i++) {
    193             Preference pref = getPreferenceScreen().getPreference(i);
    194             if (pref instanceof AccountPreference) {
    195                 Account account = ((AccountPreference) pref).getAccount();
    196                 // For all available sync authorities, sync those that are enabled for the account
    197                 for (int j = 0; j < syncAdapters.length; j++) {
    198                     SyncAdapterType sa = syncAdapters[j];
    199                     if (syncAdapters[j].accountType.equals(mAccountType)
    200                             && ContentResolver.getSyncAutomatically(account, sa.authority)) {
    201                         if (sync) {
    202                             ContentResolver.requestSync(account, sa.authority, extras);
    203                         } else {
    204                             ContentResolver.cancelSync(account, sa.authority);
    205                         }
    206                     }
    207                 }
    208             }
    209         }
    210     }
    211 
    212     @Override
    213     protected void onSyncStateUpdated() {
    214         // Catch any delayed delivery of update messages
    215         if (getActivity() == null) return;
    216 
    217         // iterate over all the preferences, setting the state properly for each
    218         SyncInfo currentSync = ContentResolver.getCurrentSync();
    219 
    220         boolean anySyncFailed = false; // true if sync on any account failed
    221         Date date = new Date();
    222 
    223         // only track userfacing sync adapters when deciding if account is synced or not
    224         final SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes();
    225         HashSet<String> userFacing = new HashSet<String>();
    226         for (int k = 0, n = syncAdapters.length; k < n; k++) {
    227             final SyncAdapterType sa = syncAdapters[k];
    228             if (sa.isUserVisible()) {
    229                 userFacing.add(sa.authority);
    230             }
    231         }
    232         for (int i = 0, count = getPreferenceScreen().getPreferenceCount(); i < count; i++) {
    233             Preference pref = getPreferenceScreen().getPreference(i);
    234             if (! (pref instanceof AccountPreference)) {
    235                 continue;
    236             }
    237 
    238             AccountPreference accountPref = (AccountPreference) pref;
    239             Account account = accountPref.getAccount();
    240             int syncCount = 0;
    241             long lastSuccessTime = 0;
    242             boolean syncIsFailing = false;
    243             final ArrayList<String> authorities = accountPref.getAuthorities();
    244             boolean syncingNow = false;
    245             if (authorities != null) {
    246                 for (String authority : authorities) {
    247                     SyncStatusInfo status = ContentResolver.getSyncStatus(account, authority);
    248                     boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority)
    249                             && ContentResolver.getMasterSyncAutomatically()
    250                             && (ContentResolver.getIsSyncable(account, authority) > 0);
    251                     boolean authorityIsPending = ContentResolver.isSyncPending(account, authority);
    252                     boolean activelySyncing = currentSync != null
    253                             && currentSync.authority.equals(authority)
    254                             && new Account(currentSync.account.name, currentSync.account.type)
    255                                     .equals(account);
    256                     boolean lastSyncFailed = status != null
    257                             && syncEnabled
    258                             && status.lastFailureTime != 0
    259                             && status.getLastFailureMesgAsInt(0)
    260                                != ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
    261                     if (lastSyncFailed && !activelySyncing && !authorityIsPending) {
    262                         syncIsFailing = true;
    263                         anySyncFailed = true;
    264                     }
    265                     syncingNow |= activelySyncing;
    266                     if (status != null && lastSuccessTime < status.lastSuccessTime) {
    267                         lastSuccessTime = status.lastSuccessTime;
    268                     }
    269                     syncCount += syncEnabled && userFacing.contains(authority) ? 1 : 0;
    270                 }
    271             } else {
    272                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
    273                     Log.v(TAG, "no syncadapters found for " + account);
    274                 }
    275             }
    276             if (syncIsFailing) {
    277                 accountPref.setSyncStatus(AccountPreference.SYNC_ERROR, true);
    278             } else if (syncCount == 0) {
    279                 accountPref.setSyncStatus(AccountPreference.SYNC_DISABLED, true);
    280             } else if (syncCount > 0) {
    281                 if (syncingNow) {
    282                     accountPref.setSyncStatus(AccountPreference.SYNC_IN_PROGRESS, true);
    283                 } else {
    284                     accountPref.setSyncStatus(AccountPreference.SYNC_ENABLED, true);
    285                     if (lastSuccessTime > 0) {
    286                         accountPref.setSyncStatus(AccountPreference.SYNC_ENABLED, false);
    287                         date.setTime(lastSuccessTime);
    288                         final String timeString = formatSyncDate(date);
    289                         accountPref.setSummary(getResources().getString(
    290                                 R.string.last_synced, timeString));
    291                     }
    292                 }
    293             } else {
    294                 accountPref.setSyncStatus(AccountPreference.SYNC_DISABLED, true);
    295             }
    296         }
    297 
    298         mErrorInfoView.setVisibility(anySyncFailed ? View.VISIBLE : View.GONE);
    299     }
    300 
    301     @Override
    302     public void onAccountsUpdated(Account[] accounts) {
    303         if (getActivity() == null) return;
    304         getPreferenceScreen().removeAll();
    305         mFirstAccount = null;
    306         addPreferencesFromResource(R.xml.manage_accounts_settings);
    307         for (int i = 0, n = accounts.length; i < n; i++) {
    308             final Account account = accounts[i];
    309             // If an account type is specified for this screen, skip other types
    310             if (mAccountType != null && !account.type.equals(mAccountType)) continue;
    311             final ArrayList<String> auths = getAuthoritiesForAccountType(account.type);
    312 
    313             boolean showAccount = true;
    314             if (mAuthorities != null && auths != null) {
    315                 showAccount = false;
    316                 for (String requestedAuthority : mAuthorities) {
    317                     if (auths.contains(requestedAuthority)) {
    318                         showAccount = true;
    319                         break;
    320                     }
    321                 }
    322             }
    323 
    324             if (showAccount) {
    325                 final Drawable icon = getDrawableForType(account.type);
    326                 final AccountPreference preference =
    327                         new AccountPreference(getActivity(), account, icon, auths, false);
    328                 getPreferenceScreen().addPreference(preference);
    329                 if (mFirstAccount == null) {
    330                     mFirstAccount = account;
    331                 }
    332             }
    333         }
    334         if (mAccountType != null && mFirstAccount != null) {
    335             addAuthenticatorSettings();
    336         } else {
    337             // There's no account, reset to top-level of settings
    338             Intent settingsTop = new Intent(android.provider.Settings.ACTION_SETTINGS);
    339             settingsTop.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    340             getActivity().startActivity(settingsTop);
    341         }
    342         onSyncStateUpdated();
    343     }
    344 
    345     private void addAuthenticatorSettings() {
    346         PreferenceScreen prefs = addPreferencesForType(mAccountType, getPreferenceScreen());
    347         if (prefs != null) {
    348             updatePreferenceIntents(prefs);
    349         }
    350     }
    351 
    352     private void updatePreferenceIntents(PreferenceScreen prefs) {
    353         PackageManager pm = getActivity().getPackageManager();
    354         for (int i = 0; i < prefs.getPreferenceCount();) {
    355             Intent intent = prefs.getPreference(i).getIntent();
    356             if (intent != null) {
    357                 ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
    358                 if (ri == null) {
    359                     prefs.removePreference(prefs.getPreference(i));
    360                     continue;
    361                 } else {
    362                     intent.putExtra(ACCOUNT_KEY, mFirstAccount);
    363                     intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
    364                 }
    365             }
    366             i++;
    367         }
    368     }
    369 
    370     @Override
    371     protected void onAuthDescriptionsUpdated() {
    372         // Update account icons for all account preference items
    373         for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
    374             Preference pref = getPreferenceScreen().getPreference(i);
    375             if (pref instanceof AccountPreference) {
    376                 AccountPreference accPref = (AccountPreference) pref;
    377                 accPref.setSummary(getLabelForType(accPref.getAccount().type));
    378             }
    379         }
    380     }
    381 }
    382