ManageAccountsSettings.java revision 855d216dd4abcf1d7f597f8cae21a44d49607eec
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 17package com.android.settings.accounts; 18 19import com.android.settings.AccountPreference; 20import com.android.settings.DialogCreatable; 21import com.android.settings.R; 22import com.android.settings.vpn.VpnTypeSelection; 23import com.google.android.collect.Maps; 24 25import android.accounts.Account; 26import android.accounts.AccountManager; 27import android.accounts.AuthenticatorDescription; 28import android.accounts.OnAccountsUpdateListener; 29import android.app.Activity; 30import android.app.AlertDialog; 31import android.app.Dialog; 32import android.content.ContentResolver; 33import android.content.Context; 34import android.content.DialogInterface; 35import android.content.Intent; 36import android.content.SyncAdapterType; 37import android.content.SyncInfo; 38import android.content.SyncStatusInfo; 39import android.content.pm.PackageManager; 40import android.graphics.drawable.Drawable; 41import android.net.ConnectivityManager; 42import android.os.Bundle; 43import android.preference.CheckBoxPreference; 44import android.preference.Preference; 45import android.preference.PreferenceActivity; 46import android.preference.PreferenceCategory; 47import android.preference.PreferenceScreen; 48import android.util.Log; 49import android.view.LayoutInflater; 50import android.view.Menu; 51import android.view.MenuInflater; 52import android.view.MenuItem; 53import android.view.View; 54import android.view.ViewGroup; 55import android.widget.Button; 56import android.widget.TextView; 57 58import java.util.ArrayList; 59import java.util.HashMap; 60import java.util.HashSet; 61import java.util.Map; 62 63public class ManageAccountsSettings extends AccountPreferenceBase 64 implements OnAccountsUpdateListener, DialogCreatable { 65 66 private static final String TAG = ManageAccountsSettings.class.getSimpleName(); 67 68 private static final String AUTHORITIES_FILTER_KEY = "authorities"; 69 private static final boolean LDEBUG = Log.isLoggable(TAG, Log.DEBUG); 70 71 private static final String AUTO_SYNC_CHECKBOX_KEY = "syncAutomaticallyCheckBox"; 72 private static final String MANAGE_ACCOUNTS_CATEGORY_KEY = "manageAccountsCategory"; 73 private static final String BACKGROUND_DATA_CHECKBOX_KEY = "backgroundDataCheckBox"; 74 private static final int DIALOG_DISABLE_BACKGROUND_DATA = 1; 75 76 private static final int MENU_ADD_ACCOUNT = Menu.FIRST; 77 78 private static final int REQUEST_SHOW_SYNC_SETTINGS = 1; 79 80 private CheckBoxPreference mBackgroundDataCheckBox; 81 private PreferenceCategory mManageAccountsCategory; 82 private String[] mAuthorities; 83 private TextView mErrorInfoView; 84 private Button mAddAccountButton; 85 private CheckBoxPreference mAutoSyncCheckbox; 86 87 private SettingsDialogFragment mDialogFragment; 88 89 private AuthenticatorDescription[] mAuthDescs; 90 private Map<String, AuthenticatorDescription> mTypeToAuthDescription 91 = new HashMap<String, AuthenticatorDescription>(); 92 private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null; 93 94 @Override 95 public void onCreate(Bundle icicle) { 96 super.onCreate(icicle); 97 98 addPreferencesFromResource(R.xml.manage_accounts_settings); 99 setHasOptionsMenu(true); 100 } 101 102 @Override 103 public void onStart() { 104 super.onStart(); 105 AccountManager.get(getActivity()).addOnAccountsUpdatedListener(this, null, true); 106 } 107 108 @Override 109 public View onCreateView(LayoutInflater inflater, ViewGroup container, 110 Bundle savedInstanceState) { 111 final View view = inflater.inflate(R.layout.manage_accounts_screen, container, false); 112 return view; 113 } 114 115 @Override 116 public void onActivityCreated(Bundle savedInstanceState) { 117 super.onActivityCreated(savedInstanceState); 118 119 final Activity activity = getActivity(); 120 final View view = getView(); 121 122 mErrorInfoView = (TextView)view.findViewById(R.id.sync_settings_error_info); 123 mErrorInfoView.setVisibility(View.GONE); 124 mErrorInfoView.setCompoundDrawablesWithIntrinsicBounds( 125 activity.getResources().getDrawable(R.drawable.ic_list_syncerror), 126 null, null, null); 127 128 mBackgroundDataCheckBox = (CheckBoxPreference) findPreference(BACKGROUND_DATA_CHECKBOX_KEY); 129 mAutoSyncCheckbox = (CheckBoxPreference) findPreference(AUTO_SYNC_CHECKBOX_KEY); 130 131 mManageAccountsCategory = (PreferenceCategory)findPreference(MANAGE_ACCOUNTS_CATEGORY_KEY); 132 mAuthorities = activity.getIntent().getStringArrayExtra(AUTHORITIES_FILTER_KEY); 133 134 updateAuthDescriptions(); 135 } 136 137 @Override 138 public void onStop() { 139 super.onStop(); 140 AccountManager.get(getActivity()).removeOnAccountsUpdatedListener(this); 141 } 142 143 @Override 144 public boolean onPreferenceTreeClick(PreferenceScreen preferences, Preference preference) { 145 if (preference == mBackgroundDataCheckBox) { 146 final ConnectivityManager connManager = (ConnectivityManager) 147 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 148 final boolean oldBackgroundDataSetting = connManager.getBackgroundDataSetting(); 149 final boolean backgroundDataSetting = mBackgroundDataCheckBox.isChecked(); 150 if (oldBackgroundDataSetting != backgroundDataSetting) { 151 if (backgroundDataSetting) { 152 setBackgroundDataInt(true); 153 onSyncStateUpdated(); 154 } else { 155 // This will get unchecked only if the user hits "Ok" 156 mBackgroundDataCheckBox.setChecked(true); 157 showDialog(DIALOG_DISABLE_BACKGROUND_DATA); 158 } 159 } 160 } else if (preference == mAutoSyncCheckbox) { 161 ContentResolver.setMasterSyncAutomatically(mAutoSyncCheckbox.isChecked()); 162 onSyncStateUpdated(); 163 } else if (preference instanceof AccountPreference) { 164 startAccountSettings((AccountPreference) preference); 165 } else { 166 return false; 167 } 168 return true; 169 } 170 171 private void startAccountSettings(AccountPreference acctPref) { 172 Bundle args = new Bundle(); 173 args.putParcelable(AccountSyncSettings.ACCOUNT_KEY, acctPref.getAccount()); 174 ((PreferenceActivity) getActivity()).startPreferencePanel( 175 AccountSyncSettings.class.getCanonicalName(), args, 176 R.string.account_sync_settings_title, acctPref.getAccount().name, 177 this, REQUEST_SHOW_SYNC_SETTINGS); 178 } 179 180 @Override 181 public Dialog onCreateDialog(int id) { 182 switch (id) { 183 case DIALOG_DISABLE_BACKGROUND_DATA: 184 final CheckBoxPreference pref = 185 (CheckBoxPreference) findPreference(BACKGROUND_DATA_CHECKBOX_KEY); 186 return new AlertDialog.Builder(getActivity()) 187 .setTitle(R.string.background_data_dialog_title) 188 .setIcon(android.R.drawable.ic_dialog_alert) 189 .setMessage(R.string.background_data_dialog_message) 190 .setPositiveButton(android.R.string.ok, 191 new DialogInterface.OnClickListener() { 192 public void onClick(DialogInterface dialog, int which) { 193 setBackgroundDataInt(false); 194 pref.setChecked(false); 195 onSyncStateUpdated(); 196 } 197 }) 198 .setNegativeButton(android.R.string.cancel, null) 199 .create(); 200 } 201 202 return null; 203 } 204 205 public void showDialog(int dialogId) { 206 if (mDialogFragment != null) { 207 Log.e(TAG, "Old dialog fragment not null!"); 208 } 209 mDialogFragment = new SettingsDialogFragment(this, dialogId); 210 mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); 211 } 212 213 @Override 214 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 215 MenuItem actionItem = 216 menu.add(0, MENU_ADD_ACCOUNT, 0, R.string.add_account_label) 217 .setIcon(R.drawable.ic_menu_add); 218 actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM 219 | MenuItem.SHOW_AS_ACTION_WITH_TEXT); 220 } 221 222 @Override 223 public boolean onOptionsItemSelected(MenuItem item) { 224 if (item.getItemId() == MENU_ADD_ACCOUNT) { 225 onAddAccountClicked(); 226 return true; 227 } else { 228 return super.onOptionsItemSelected(item); 229 } 230 } 231 232 private void setBackgroundDataInt(boolean enabled) { 233 final ConnectivityManager connManager = (ConnectivityManager) 234 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 235 connManager.setBackgroundDataSetting(enabled); 236 } 237 238 protected void onSyncStateUpdated() { 239 // Catch any delayed delivery of update messages 240 if (getActivity() == null) return; 241 // Set background connection state 242 final ConnectivityManager connManager = (ConnectivityManager) 243 getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 244 final boolean backgroundDataSetting = connManager.getBackgroundDataSetting(); 245 mBackgroundDataCheckBox.setChecked(backgroundDataSetting); 246 boolean masterSyncAutomatically = ContentResolver.getMasterSyncAutomatically(); 247 mAutoSyncCheckbox.setChecked(masterSyncAutomatically); 248 249 // iterate over all the preferences, setting the state properly for each 250 SyncInfo currentSync = ContentResolver.getCurrentSync(); 251 252 boolean anySyncFailed = false; // true if sync on any account failed 253 254 // only track userfacing sync adapters when deciding if account is synced or not 255 final SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes(); 256 HashSet<String> userFacing = new HashSet<String>(); 257 for (int k = 0, n = syncAdapters.length; k < n; k++) { 258 final SyncAdapterType sa = syncAdapters[k]; 259 if (sa.isUserVisible()) { 260 userFacing.add(sa.authority); 261 } 262 } 263 for (int i = 0, count = mManageAccountsCategory.getPreferenceCount(); i < count; i++) { 264 Preference pref = mManageAccountsCategory.getPreference(i); 265 if (! (pref instanceof AccountPreference)) { 266 continue; 267 } 268 269 AccountPreference accountPref = (AccountPreference) pref; 270 Account account = accountPref.getAccount(); 271 int syncCount = 0; 272 boolean syncIsFailing = false; 273 final ArrayList<String> authorities = accountPref.getAuthorities(); 274 if (authorities != null) { 275 for (String authority : authorities) { 276 SyncStatusInfo status = ContentResolver.getSyncStatus(account, authority); 277 boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority) 278 && masterSyncAutomatically 279 && backgroundDataSetting 280 && (ContentResolver.getIsSyncable(account, authority) > 0); 281 boolean authorityIsPending = ContentResolver.isSyncPending(account, authority); 282 boolean activelySyncing = currentSync != null 283 && currentSync.authority.equals(authority) 284 && new Account(currentSync.account.name, currentSync.account.type) 285 .equals(account); 286 boolean lastSyncFailed = status != null 287 && syncEnabled 288 && status.lastFailureTime != 0 289 && status.getLastFailureMesgAsInt(0) 290 != ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS; 291 if (lastSyncFailed && !activelySyncing && !authorityIsPending) { 292 syncIsFailing = true; 293 anySyncFailed = true; 294 } 295 syncCount += syncEnabled && userFacing.contains(authority) ? 1 : 0; 296 } 297 } else { 298 if (Log.isLoggable(TAG, Log.VERBOSE)) { 299 Log.v(TAG, "no syncadapters found for " + account); 300 } 301 } 302 int syncStatus = AccountPreference.SYNC_DISABLED; 303 if (syncIsFailing) { 304 syncStatus = AccountPreference.SYNC_ERROR; 305 } else if (syncCount == 0) { 306 syncStatus = AccountPreference.SYNC_DISABLED; 307 } else if (syncCount > 0) { 308 syncStatus = AccountPreference.SYNC_ENABLED; 309 } 310 accountPref.setSyncStatus(syncStatus); 311 } 312 313 mErrorInfoView.setVisibility(anySyncFailed ? View.VISIBLE : View.GONE); 314 } 315 316 @Override 317 public void onAccountsUpdated(Account[] accounts) { 318 mManageAccountsCategory.removeAll(); 319 for (int i = 0, n = accounts.length; i < n; i++) { 320 final Account account = accounts[i]; 321 final ArrayList<String> auths = getAuthoritiesForAccountType(account.type); 322 323 boolean showAccount = true; 324 if (mAuthorities != null && auths != null) { 325 showAccount = false; 326 for (String requestedAuthority : mAuthorities) { 327 if (auths.contains(requestedAuthority)) { 328 showAccount = true; 329 break; 330 } 331 } 332 } 333 334 if (showAccount) { 335 final Drawable icon = getDrawableForType(account.type); 336 final AccountPreference preference = 337 new AccountPreference(getActivity(), account, icon, auths); 338 mManageAccountsCategory.addPreference(preference); 339 } 340 } 341 onSyncStateUpdated(); 342 } 343 344 protected void onAuthDescriptionsUpdated() { 345 // Update account icons for all account preference items 346 for (int i = 0; i < mManageAccountsCategory.getPreferenceCount(); i++) { 347 AccountPreference pref = (AccountPreference) mManageAccountsCategory.getPreference(i); 348 pref.setProviderIcon(getDrawableForType(pref.getAccount().type)); 349 pref.setSummary(getLabelForType(pref.getAccount().type)); 350 } 351 } 352 353 public void onAddAccountClicked() { 354 Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); 355 intent.putExtra(AUTHORITIES_FILTER_KEY, mAuthorities); 356 startActivity(intent); 357 } 358} 359