• 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 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
onCreate(Bundle icicle)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
onStart()94     public void onStart() {
95         super.onStart();
96         Activity activity = getActivity();
97         AccountManager.get(activity).addOnAccountsUpdatedListener(this, null, true);
98     }
99 
100     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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
onActivityCreated(Bundle savedInstanceState)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
onStop()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
onPreferenceTreeClick(PreferenceScreen preferences, Preference preference)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 
startAccountSettings(AccountPreference acctPref)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
onCreateOptionsMenu(Menu menu, MenuInflater inflater)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
onPrepareOptionsMenu(Menu menu)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
onOptionsItemSelected(MenuItem item)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 
requestOrCancelSyncForAccounts(boolean sync)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
onSyncStateUpdated()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
onAccountsUpdated(Account[] accounts)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 
addAuthenticatorSettings()345     private void addAuthenticatorSettings() {
346         PreferenceScreen prefs = addPreferencesForType(mAccountType, getPreferenceScreen());
347         if (prefs != null) {
348             updatePreferenceIntents(prefs);
349         }
350     }
351 
updatePreferenceIntents(PreferenceScreen prefs)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
onAuthDescriptionsUpdated()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