diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/settings/AccountPreference.java | 40 | ||||
-rw-r--r-- | src/com/android/settings/DataUsageSummary.java | 49 | ||||
-rw-r--r-- | src/com/android/settings/Settings.java | 112 | ||||
-rw-r--r-- | src/com/android/settings/accounts/AccountPreferenceBase.java | 97 | ||||
-rw-r--r-- | src/com/android/settings/accounts/AccountSyncSettings.java | 56 | ||||
-rw-r--r-- | src/com/android/settings/accounts/AuthenticatorHelper.java | 127 | ||||
-rw-r--r-- | src/com/android/settings/accounts/ManageAccountsSettings.java | 190 |
7 files changed, 470 insertions, 201 deletions
diff --git a/src/com/android/settings/AccountPreference.java b/src/com/android/settings/AccountPreference.java index 824420d..e7919dd 100644 --- a/src/com/android/settings/AccountPreference.java +++ b/src/com/android/settings/AccountPreference.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import android.accounts.Account; import android.content.Context; -import android.content.Intent; import android.graphics.drawable.Drawable; import android.preference.Preference; import android.util.Log; @@ -36,25 +35,20 @@ public class AccountPreference extends Preference { public static final int SYNC_ENABLED = 0; // all know sync adapters are enabled and OK public static final int SYNC_DISABLED = 1; // no sync adapters are enabled public static final int SYNC_ERROR = 2; // one or more sync adapters have a problem + public static final int SYNC_IN_PROGRESS = 3; // currently syncing private int mStatus; private Account mAccount; private ArrayList<String> mAuthorities; - private Drawable mProviderIcon; - private ImageView mSyncStatusIcon; - private ImageView mProviderIconView; public AccountPreference(Context context, Account account, Drawable icon, ArrayList<String> authorities) { super(context); mAccount = account; mAuthorities = authorities; - mProviderIcon = icon; - setWidgetLayoutResource(R.layout.account_preference); setTitle(mAccount.name); setSummary(""); setPersistent(false); setSyncStatus(SYNC_DISABLED); - setIcon(mProviderIcon); } public Account getAccount() { @@ -69,23 +63,14 @@ public class AccountPreference extends Preference { protected void onBindView(View view) { super.onBindView(view); setSummary(getSyncStatusMessage(mStatus)); - mSyncStatusIcon = (ImageView) view.findViewById(R.id.syncStatusIcon); - mSyncStatusIcon.setImageResource(getSyncStatusIcon(mStatus)); - mSyncStatusIcon.setContentDescription(getSyncContentDescription(mStatus)); - } - - public void setProviderIcon(Drawable icon) { - mProviderIcon = icon; - if (mProviderIconView != null) { - mProviderIconView.setImageDrawable(icon); - } + ImageView iconView = (ImageView) view.findViewById(android.R.id.icon); + iconView.setImageResource(getSyncStatusIcon(mStatus)); + iconView.setContentDescription(getSyncContentDescription(mStatus)); } public void setSyncStatus(int status) { mStatus = status; - if (mSyncStatusIcon != null) { - mSyncStatusIcon.setImageResource(getSyncStatusIcon(status)); - } + setIcon(getSyncStatusIcon(status)); setSummary(getSyncStatusMessage(status)); } @@ -101,6 +86,9 @@ public class AccountPreference extends Preference { case SYNC_ERROR: res = R.string.sync_error; break; + case SYNC_IN_PROGRESS: + res = R.string.sync_in_progress; + break; default: res = R.string.sync_error; Log.e(TAG, "Unknown sync status: " + status); @@ -120,6 +108,9 @@ public class AccountPreference extends Preference { case SYNC_ERROR: res = R.drawable.ic_sync_red_holo; break; + case SYNC_IN_PROGRESS: + res = R.drawable.ic_sync_grey_holo; + break; default: res = R.drawable.ic_sync_red_holo; Log.e(TAG, "Unknown sync status: " + status); @@ -140,13 +131,4 @@ public class AccountPreference extends Preference { return getContext().getString(R.string.accessibility_sync_error); } } - - @Override - public int compareTo(Preference other) { - if (!(other instanceof AccountPreference)) { - // Put other preference types above us - return 1; - } - return mAccount.name.compareTo(((AccountPreference) other).mAccount.name); - } } diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index c58e001..656d4c4 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -178,6 +178,7 @@ public class DataUsageSummary extends Fragment { private static final String TAG_CONFIRM_RESTRICT = "confirmRestrict"; private static final String TAG_DENIED_RESTRICT = "deniedRestrict"; private static final String TAG_CONFIRM_APP_RESTRICT = "confirmAppRestrict"; + private static final String TAG_CONFIRM_AUTO_SYNC_CHANGE = "confirmAutoSyncChange"; private static final String TAG_APP_DETAILS = "appDetails"; private static final int LOADER_CHART_DATA = 2; @@ -251,6 +252,7 @@ public class DataUsageSummary extends Fragment { private MenuItem mMenuDataRoaming; private MenuItem mMenuRestrictBackground; + private MenuItem mMenuAutoSync; /** Flag used to ignore listeners during binding. */ private boolean mBinding; @@ -453,6 +455,9 @@ public class DataUsageSummary extends Fragment { mMenuRestrictBackground.setVisible(hasReadyMobileRadio(context) && !appDetailMode); mMenuRestrictBackground.setChecked(mPolicyManager.getRestrictBackground()); + mMenuAutoSync = menu.findItem(R.id.data_usage_menu_auto_sync); + mMenuAutoSync.setChecked(ContentResolver.getMasterSyncAutomatically()); + final MenuItem split4g = menu.findItem(R.id.data_usage_menu_split_4g); split4g.setVisible(hasReadyMobile4gRadio(context) && !appDetailMode); split4g.setChecked(isMobilePolicySplit()); @@ -543,6 +548,10 @@ public class DataUsageSummary extends Fragment { R.string.data_usage_metered_title, null, this, 0); return true; } + case R.id.data_usage_menu_auto_sync: { + ConfirmAutoSyncChangeFragment.show(this, !item.isChecked()); + return true; + } } return false; } @@ -2023,6 +2032,46 @@ public class DataUsageSummary extends Fragment { } /** + * Dialog to inform user about changing auto-sync setting + */ + public static class ConfirmAutoSyncChangeFragment extends DialogFragment { + private boolean mEnabling; + + public static void show(DataUsageSummary parent, boolean enabling) { + if (!parent.isAdded()) return; + + final ConfirmAutoSyncChangeFragment dialog = new ConfirmAutoSyncChangeFragment(); + dialog.mEnabling = enabling; + dialog.setTargetFragment(parent, 0); + dialog.show(parent.getFragmentManager(), TAG_CONFIRM_AUTO_SYNC_CHANGE); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Context context = getActivity(); + + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + if (!mEnabling) { + builder.setTitle(R.string.data_usage_auto_sync_off_dialog_title); + builder.setMessage(R.string.data_usage_auto_sync_off_dialog); + } else { + builder.setTitle(R.string.data_usage_auto_sync_on_dialog_title); + builder.setMessage(R.string.data_usage_auto_sync_on_dialog); + } + + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ContentResolver.setMasterSyncAutomatically(mEnabling); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + + return builder.create(); + } + } + + /** * Compute default tab that should be selected, based on * {@link NetworkPolicyManager#EXTRA_NETWORK_TEMPLATE} extra. */ diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index b36364d..a8599bf 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -18,6 +18,8 @@ package com.android.settings; import com.android.internal.util.ArrayUtils; import com.android.settings.accounts.AccountSyncSettings; +import com.android.settings.accounts.AuthenticatorHelper; +import com.android.settings.accounts.ManageAccountsSettings; import com.android.settings.applications.ManageApplications; import com.android.settings.bluetooth.BluetoothEnabler; import com.android.settings.deviceinfo.Memory; @@ -30,6 +32,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.INetworkManagementService; import android.os.RemoteException; @@ -37,6 +40,7 @@ import android.os.ServiceManager; import android.os.UserId; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.preference.PreferenceActivity.Header; import android.preference.PreferenceFragment; import android.text.TextUtils; import android.util.Log; @@ -52,6 +56,8 @@ import android.widget.Switch; import android.widget.TextView; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -89,7 +95,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { R.id.sound_settings, R.id.display_settings, R.id.security_settings, - R.id.sync_settings, + R.id.account_settings, R.id.about_settings }; @@ -100,6 +106,9 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>(); private List<Header> mHeaders; + private AuthenticatorHelper mAuthenticatorHelper; + private Header mLastHeader; + @Override protected void onCreate(Bundle savedInstanceState) { if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) { @@ -111,13 +120,17 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { mEnableUserManagement = true; } + mAuthenticatorHelper = new AuthenticatorHelper(); + mAuthenticatorHelper.updateAuthDescriptions(this); + mAuthenticatorHelper.onAccountsUpdated(this, null); + getMetaData(); mInLocalHeaderSwitch = true; super.onCreate(savedInstanceState); mInLocalHeaderSwitch = false; if (!onIsHidingHeaders() && onIsMultiPane()) { - highlightHeader(); + highlightHeader(mTopLevelHeaderId); // Force the title so that it doesn't get overridden by a direct launch of // a specific settings screen. setTitle(R.string.settings_label); @@ -217,7 +230,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { mCurrentHeader = parentHeader; switchToHeaderLocal(parentHeader); - highlightHeader(); + highlightHeader(mTopLevelHeaderId); mParentHeader = new Header(); mParentHeader.fragment @@ -240,9 +253,9 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { } } - private void highlightHeader() { - if (mTopLevelHeaderId != 0) { - Integer index = mHeaderIndexMap.get(mTopLevelHeaderId); + private void highlightHeader(int id) { + if (id != 0) { + Integer index = mHeaderIndexMap.get(id); if (index != null) { getListView().setItemChecked(index, true); getListView().smoothScrollToPosition(index); @@ -326,7 +339,8 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { ManageApplications.class.getName().equals(fragmentName) || WirelessSettings.class.getName().equals(fragmentName) || SoundSettings.class.getName().equals(fragmentName) || - PrivacySettings.class.getName().equals(fragmentName)) { + PrivacySettings.class.getName().equals(fragmentName) || + ManageAccountsSettings.class.getName().equals(fragmentName)) { intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true); } @@ -378,6 +392,9 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { } catch (RemoteException e) { // ignored } + } else if (id == R.id.account_settings) { + int headerIndex = i + 1; + i = insertAccountsHeaders(target, headerIndex); } else if (id == R.id.user_settings) { if (!mEnableUserManagement || !UserId.MU_ENABLED || UserId.myUserId() != 0 @@ -404,6 +421,44 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { } } + private int insertAccountsHeaders(List<Header> target, int headerIndex) { + String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes(); + List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length); + for (String accountType : accountTypes) { + CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType); + Header accHeader = new Header(); + accHeader.title = label; + if (accHeader.extras == null) { + accHeader.extras = new Bundle(); + } + accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); + accHeader.breadCrumbTitle = label; + accHeader.breadCrumbShortTitle = label; + accHeader.fragment = ManageAccountsSettings.class.getName(); + accHeader.fragmentArguments = new Bundle(); + accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, + accountType); + if (!isMultiPane()) { + accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, + label.toString()); + } + accountHeaders.add(accHeader); + } + + // Sort by label + Collections.sort(accountHeaders, new Comparator<Header>() { + @Override + public int compare(Header h1, Header h2) { + return h1.title.toString().compareTo(h2.title.toString()); + } + }); + + for (Header header : accountHeaders) { + target.add(headerIndex++, header); + } + return headerIndex; + } + private boolean needsDockSettings() { return getResources().getBoolean(R.bool.has_dock_settings); } @@ -415,7 +470,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { if (ai == null || ai.metaData == null) return; mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID); mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS); - + // Check if it has a parent specified and create a Header object final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE); String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS); @@ -449,6 +504,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { private final WifiEnabler mWifiEnabler; private final BluetoothEnabler mBluetoothEnabler; + private AuthenticatorHelper mAuthHelper; private static class HeaderViewHolder { ImageView icon; @@ -495,10 +551,13 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { return true; } - public HeaderAdapter(Context context, List<Header> objects) { + public HeaderAdapter(Context context, List<Header> objects, + AuthenticatorHelper authenticatorHelper) { super(context, 0, objects); + + mAuthHelper = authenticatorHelper; mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - + // Temp Switches provided as placeholder until the adapter replaces these with actual // Switches inflated from their layouts. Must be done before adapter is set in super mWifiEnabler = new WifiEnabler(context, new Switch(context)); @@ -566,7 +625,20 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { //$FALL-THROUGH$ case HEADER_TYPE_NORMAL: - holder.icon.setImageResource(header.iconRes); + if (header.extras != null && header.extras.containsKey( + ManageAccountsSettings.KEY_ACCOUNT_TYPE)) { + String accType = header.extras.getString( + ManageAccountsSettings.KEY_ACCOUNT_TYPE); + ViewGroup.LayoutParams lp = holder.icon.getLayoutParams(); + lp.width = getContext().getResources().getDimensionPixelSize( + R.dimen.header_icon_width); + lp.height = lp.width; + holder.icon.setLayoutParams(lp); + Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType); + holder.icon.setImageDrawable(icon); + } else { + holder.icon.setImageResource(header.iconRes); + } holder.title.setText(header.getTitle(getContext().getResources())); CharSequence summary = header.getSummary(getContext().getResources()); if (!TextUtils.isEmpty(summary)) { @@ -593,6 +665,22 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { } @Override + public void onHeaderClick(Header header, int position) { + boolean revert = false; + if (header.id == R.id.account_add) { + revert = true; + } + + super.onHeaderClick(header, position); + + if (revert && mLastHeader != null) { + highlightHeader((int) mLastHeader.id); + } else { + mLastHeader = header; + } + } + + @Override public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) { // Override the fragment title for Wallpaper settings int titleRes = pref.getTitleRes(); @@ -620,7 +708,7 @@ public class Settings extends PreferenceActivity implements ButtonBarHandler { } // Ignore the adapter provided by PreferenceActivity and substitute ours instead - super.setListAdapter(new HeaderAdapter(this, mHeaders)); + super.setListAdapter(new HeaderAdapter(this, mHeaders, mAuthenticatorHelper)); } /* diff --git a/src/com/android/settings/accounts/AccountPreferenceBase.java b/src/com/android/settings/accounts/AccountPreferenceBase.java index a0d6a7f..2759a8f 100644 --- a/src/com/android/settings/accounts/AccountPreferenceBase.java +++ b/src/com/android/settings/accounts/AccountPreferenceBase.java @@ -17,6 +17,7 @@ package com.android.settings.accounts; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -27,6 +28,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; import android.accounts.OnAccountsUpdateListener; +import android.app.Activity; import android.content.ContentResolver; import android.content.Context; import android.content.SyncAdapterType; @@ -38,6 +40,7 @@ import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import android.text.format.DateFormat; import android.util.Log; class AccountPreferenceBase extends SettingsPreferenceFragment @@ -46,12 +49,12 @@ class AccountPreferenceBase extends SettingsPreferenceFragment protected static final String TAG = "AccountSettings"; public static final String AUTHORITIES_FILTER_KEY = "authorities"; public static final String ACCOUNT_TYPES_FILTER_KEY = "account_types"; - private Map<String, AuthenticatorDescription> mTypeToAuthDescription - = new HashMap<String, AuthenticatorDescription>(); - protected AuthenticatorDescription[] mAuthDescs; private final Handler mHandler = new Handler(); private Object mStatusChangeListenerHandle; private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null; + private AuthenticatorHelper mAuthenticatorHelper = new AuthenticatorHelper(); + private java.text.DateFormat mDateFormat; + private java.text.DateFormat mTimeFormat; /** * Overload to handle account updates. @@ -75,6 +78,16 @@ class AccountPreferenceBase extends SettingsPreferenceFragment } @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final Activity activity = getActivity(); + + mDateFormat = DateFormat.getDateFormat(activity); + mTimeFormat = DateFormat.getTimeFormat(activity); + } + + @Override public void onResume() { super.onResume(); mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener( @@ -91,7 +104,6 @@ class AccountPreferenceBase extends SettingsPreferenceFragment ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle); } - private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() { public void onStatusChanged(int which) { mHandler.post(new Runnable() { @@ -124,64 +136,21 @@ class AccountPreferenceBase extends SettingsPreferenceFragment } /** - * Gets an icon associated with a particular account type. If none found, return null. - * @param accountType the type of account - * @return a drawable for the icon or null if one cannot be found. - */ - protected Drawable getDrawableForType(final String accountType) { - Drawable icon = null; - if (mTypeToAuthDescription.containsKey(accountType)) { - try { - AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); - Context authContext = getActivity().createPackageContext(desc.packageName, 0); - icon = authContext.getResources().getDrawable(desc.iconId); - } catch (PackageManager.NameNotFoundException e) { - // TODO: place holder icon for missing account icons? - Log.w(TAG, "No icon name for account type " + accountType); - } catch (Resources.NotFoundException e) { - // TODO: place holder icon for missing account icons? - Log.w(TAG, "No icon resource for account type " + accountType); - } - } - return icon; - } - - /** - * Gets the label associated with a particular account type. If none found, return null. - * @param accountType the type of account - * @return a CharSequence for the label or null if one cannot be found. - */ - protected CharSequence getLabelForType(final String accountType) { - CharSequence label = null; - if (mTypeToAuthDescription.containsKey(accountType)) { - try { - AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); - Context authContext = getActivity().createPackageContext(desc.packageName, 0); - label = authContext.getResources().getText(desc.labelId); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "No label name for account type " + accountType); - } catch (Resources.NotFoundException e) { - Log.w(TAG, "No label icon for account type " + accountType); - } - } - return label; - } - - /** * Gets the preferences.xml file associated with a particular account type. * @param accountType the type of account * @return a PreferenceScreen inflated from accountPreferenceId. */ - protected PreferenceScreen addPreferencesForType(final String accountType) { + public PreferenceScreen addPreferencesForType(final String accountType, + PreferenceScreen parent) { PreferenceScreen prefs = null; - if (mTypeToAuthDescription.containsKey(accountType)) { + if (mAuthenticatorHelper.containsAccountType(accountType)) { AuthenticatorDescription desc = null; try { - desc = mTypeToAuthDescription.get(accountType); + desc = mAuthenticatorHelper.getAccountTypeDescription(accountType); if (desc != null && desc.accountPreferencesId != 0) { Context authContext = getActivity().createPackageContext(desc.packageName, 0); prefs = getPreferenceManager().inflateFromResource(authContext, - desc.accountPreferencesId, getPreferenceScreen()); + desc.accountPreferencesId, parent); } } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName); @@ -192,15 +161,21 @@ class AccountPreferenceBase extends SettingsPreferenceFragment return prefs; } - /** - * Updates provider icons. Subclasses should call this in onCreate() - * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). - */ - protected void updateAuthDescriptions() { - mAuthDescs = AccountManager.get(getActivity()).getAuthenticatorTypes(); - for (int i = 0; i < mAuthDescs.length; i++) { - mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); - } + public void updateAuthDescriptions() { + mAuthenticatorHelper.updateAuthDescriptions(getActivity()); onAuthDescriptionsUpdated(); } + + protected Drawable getDrawableForType(final String accountType) { + return mAuthenticatorHelper.getDrawableForType(getActivity(), accountType); + } + + protected CharSequence getLabelForType(final String accountType) { + return mAuthenticatorHelper.getLabelForType(getActivity(), accountType); + } + + protected String formatSyncDate(Date date) { + // TODO: Switch to using DateUtils.formatDateTime + return mDateFormat.format(date) + " " + mTimeFormat.format(date); + } } diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java index fda2eb1..715108b 100644 --- a/src/com/android/settings/accounts/AccountSyncSettings.java +++ b/src/com/android/settings/accounts/AccountSyncSettings.java @@ -63,9 +63,9 @@ import java.util.List; public class AccountSyncSettings extends AccountPreferenceBase { public static final String ACCOUNT_KEY = "account"; - protected static final int MENU_REMOVE_ACCOUNT_ID = Menu.FIRST; - private static final int MENU_SYNC_NOW_ID = Menu.FIRST + 1; - private static final int MENU_SYNC_CANCEL_ID = Menu.FIRST + 2; + private static final int MENU_SYNC_NOW_ID = Menu.FIRST; + private static final int MENU_SYNC_CANCEL_ID = Menu.FIRST + 1; + private static final int MENU_REMOVE_ACCOUNT_ID = Menu.FIRST + 2; private static final int REALLY_REMOVE_DIALOG = 100; private static final int FAILED_REMOVAL_DIALOG = 101; private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102; @@ -73,8 +73,6 @@ public class AccountSyncSettings extends AccountPreferenceBase { private TextView mProviderId; private ImageView mProviderIcon; private TextView mErrorInfoView; - private java.text.DateFormat mDateFormat; - private java.text.DateFormat mTimeFormat; private Account mAccount; // List of all accounts, updated when accounts are added/removed // We need to re-scan the accounts on sync events, in case sync state changes. @@ -172,11 +170,6 @@ public class AccountSyncSettings extends AccountPreferenceBase { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - final Activity activity = getActivity(); - - mDateFormat = DateFormat.getDateFormat(activity); - mTimeFormat = DateFormat.getTimeFormat(activity); - Bundle arguments = getArguments(); if (arguments == null) { Log.e(TAG, "No arguments provided when starting intent. ACCOUNT_KEY needed."); @@ -228,17 +221,16 @@ public class AccountSyncSettings extends AccountPreferenceBase { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - MenuItem removeAccount = menu.add(0, MENU_REMOVE_ACCOUNT_ID, 0, - getString(R.string.remove_account_label)) - .setIcon(R.drawable.ic_menu_delete_holo_dark); MenuItem syncNow = menu.add(0, MENU_SYNC_NOW_ID, 0, - getString(R.string.sync_menu_sync_now)) + getString(R.string.sync_menu_sync_now)) .setIcon(R.drawable.ic_menu_refresh_holo_dark); MenuItem syncCancel = menu.add(0, MENU_SYNC_CANCEL_ID, 0, - getString(R.string.sync_menu_sync_cancel)) + getString(R.string.sync_menu_sync_cancel)) .setIcon(com.android.internal.R.drawable.ic_menu_close_clear_cancel); + MenuItem removeAccount = menu.add(0, MENU_REMOVE_ACCOUNT_ID, 0, + getString(R.string.remove_account_label)) + .setIcon(R.drawable.ic_menu_delete_holo_dark); removeAccount.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT); @@ -246,6 +238,8 @@ public class AccountSyncSettings extends AccountPreferenceBase { MenuItem.SHOW_AS_ACTION_WITH_TEXT); syncCancel.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + + super.onCreateOptionsMenu(menu, inflater); } @Override @@ -397,11 +391,14 @@ public class AccountSyncSettings extends AccountPreferenceBase { } final long successEndTime = (status == null) ? 0 : status.lastSuccessTime; - if (successEndTime != 0) { + if (!syncEnabled) { + syncPref.setSummary(R.string.sync_disabled); + } else if (activelySyncing) { + syncPref.setSummary(R.string.sync_in_progress); + } else if (successEndTime != 0) { date.setTime(successEndTime); - final String timeString = mDateFormat.format(date) + " " - + mTimeFormat.format(date); - syncPref.setSummary(timeString); + final String timeString = formatSyncDate(date); + syncPref.setSummary(getResources().getString(R.string.last_synced, timeString)); } else { syncPref.setSummary(""); } @@ -501,25 +498,12 @@ public class AccountSyncSettings extends AccountPreferenceBase { if (mAccount != null) { mProviderIcon.setImageDrawable(getDrawableForType(mAccount.type)); mProviderId.setText(getLabelForType(mAccount.type)); - PreferenceScreen prefs = addPreferencesForType(mAccount.type); - if (prefs != null) { - updatePreferenceIntents(prefs); - } } addPreferencesFromResource(R.xml.account_sync_settings); } - private void updatePreferenceIntents(PreferenceScreen prefs) { - for (int i = 0; i < prefs.getPreferenceCount(); i++) { - Intent intent = prefs.getPreference(i).getIntent(); - if (intent != null) { - intent.putExtra(ACCOUNT_KEY, mAccount); - // This is somewhat of a hack. Since the preference screen we're accessing comes - // from another package, we need to modify the intent to launch it with - // FLAG_ACTIVITY_NEW_TASK. - // TODO: Do something smarter if we ever have PreferenceScreens of our own. - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); - } - } + @Override + protected int getHelpResource() { + return R.string.help_url_accounts; } } diff --git a/src/com/android/settings/accounts/AuthenticatorHelper.java b/src/com/android/settings/accounts/AuthenticatorHelper.java new file mode 100644 index 0000000..9c17a36 --- /dev/null +++ b/src/com/android/settings/accounts/AuthenticatorHelper.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accounts; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AuthenticatorDescription; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ScaleDrawable; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class AuthenticatorHelper { + + private static final String TAG = "AccountTypesHelper"; + private Map<String, AuthenticatorDescription> mTypeToAuthDescription + = new HashMap<String, AuthenticatorDescription>(); + private AuthenticatorDescription[] mAuthDescs; + private ArrayList<String> mEnabledAccountTypes = new ArrayList<String>(); + private Map<String, Drawable> mAccTypeIconCache = new HashMap<String, Drawable>(); + + public AuthenticatorHelper() { + } + + public String[] getEnabledAccountTypes() { + return mEnabledAccountTypes.toArray(new String[mEnabledAccountTypes.size()]); + } + + /** + * Gets an icon associated with a particular account type. If none found, return null. + * @param accountType the type of account + * @return a drawable for the icon or null if one cannot be found. + */ + public Drawable getDrawableForType(Context context, final String accountType) { + Drawable icon = null; + if (mAccTypeIconCache.containsKey(accountType)) { + return mAccTypeIconCache.get(accountType); + } + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + Context authContext = context.createPackageContext(desc.packageName, 0); + icon = authContext.getResources().getDrawable(desc.iconId); + mAccTypeIconCache.put(accountType, icon); + } catch (PackageManager.NameNotFoundException e) { + } catch (Resources.NotFoundException e) { + } + } + if (icon == null) { + icon = context.getPackageManager().getDefaultActivityIcon(); + } + return icon; + } + + /** + * Gets the label associated with a particular account type. If none found, return null. + * @param accountType the type of account + * @return a CharSequence for the label or null if one cannot be found. + */ + public CharSequence getLabelForType(Context context, final String accountType) { + CharSequence label = null; + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + Context authContext = context.createPackageContext(desc.packageName, 0); + label = authContext.getResources().getText(desc.labelId); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "No label name for account type " + accountType); + } catch (Resources.NotFoundException e) { + Log.w(TAG, "No label icon for account type " + accountType); + } + } + return label; + } + + /** + * Updates provider icons. Subclasses should call this in onCreate() + * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). + */ + public void updateAuthDescriptions(Context context) { + mAuthDescs = AccountManager.get(context).getAuthenticatorTypes(); + for (int i = 0; i < mAuthDescs.length; i++) { + mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); + } + } + + public void onAccountsUpdated(Context context, Account[] accounts) { + if (accounts == null) { + accounts = AccountManager.get(context).getAccounts(); + } + mEnabledAccountTypes.clear(); + mAccTypeIconCache.clear(); + for (Account account: accounts) { + if (!mEnabledAccountTypes.contains(account.type)) { + mEnabledAccountTypes.add(account.type); + } + } + } + + public boolean containsAccountType(String accountType) { + return mTypeToAuthDescription.containsKey(accountType); + } + + public AuthenticatorDescription getAccountTypeDescription(String accountType) { + return mTypeToAuthDescription.get(accountType); + } +} diff --git a/src/com/android/settings/accounts/ManageAccountsSettings.java b/src/com/android/settings/accounts/ManageAccountsSettings.java index f5e143d..909fd92 100644 --- a/src/com/android/settings/accounts/ManageAccountsSettings.java +++ b/src/com/android/settings/accounts/ManageAccountsSettings.java @@ -21,16 +21,22 @@ import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; import android.app.ActionBar; import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.SyncAdapterType; import android.content.SyncInfo; import android.content.SyncStatusInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import android.text.format.DateFormat; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -44,16 +50,21 @@ import android.widget.Switch; import android.widget.TextView; import com.android.settings.AccountPreference; -import com.android.settings.DialogCreatable; import com.android.settings.R; +import com.android.settings.Settings; import java.util.ArrayList; +import java.util.Date; import java.util.HashSet; public class ManageAccountsSettings extends AccountPreferenceBase - implements OnAccountsUpdateListener, DialogCreatable { + implements OnAccountsUpdateListener { - private static final int MENU_ADD_ACCOUNT = Menu.FIRST; + public static final String KEY_ACCOUNT_TYPE = "account_type"; + public static final String KEY_ACCOUNT_LABEL = "account_label"; + + private static final int MENU_SYNC_NOW_ID = Menu.FIRST; + private static final int MENU_SYNC_CANCEL_ID = Menu.FIRST + 1; private static final int REQUEST_SHOW_SYNC_SETTINGS = 1; @@ -61,12 +72,17 @@ public class ManageAccountsSettings extends AccountPreferenceBase private TextView mErrorInfoView; private SettingsDialogFragment mDialogFragment; - private Switch mAutoSyncSwitch; + // If an account type is set, then show only accounts of that type + private String mAccountType; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); + Bundle args = getArguments(); + if (args != null && args.containsKey(KEY_ACCOUNT_TYPE)) { + mAccountType = args.getString(KEY_ACCOUNT_TYPE); + } addPreferencesFromResource(R.xml.manage_accounts_settings); setHasOptionsMenu(true); } @@ -76,12 +92,6 @@ public class ManageAccountsSettings extends AccountPreferenceBase super.onStart(); Activity activity = getActivity(); AccountManager.get(activity).addOnAccountsUpdatedListener(this, null, true); - activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, - ActionBar.DISPLAY_SHOW_CUSTOM); - activity.getActionBar().setCustomView(mAutoSyncSwitch, new ActionBar.LayoutParams( - ActionBar.LayoutParams.WRAP_CONTENT, - ActionBar.LayoutParams.WRAP_CONTENT, - Gravity.CENTER_VERTICAL | Gravity.RIGHT)); } @Override @@ -101,23 +111,12 @@ public class ManageAccountsSettings extends AccountPreferenceBase mErrorInfoView = (TextView)view.findViewById(R.id.sync_settings_error_info); mErrorInfoView.setVisibility(View.GONE); - mAutoSyncSwitch = new Switch(activity); - - // TODO Where to put the switch in tablet multipane layout? - final int padding = activity.getResources().getDimensionPixelSize( - R.dimen.action_bar_switch_padding); - mAutoSyncSwitch.setPadding(0, 0, padding, 0); - mAutoSyncSwitch.setChecked(ContentResolver.getMasterSyncAutomatically()); - mAutoSyncSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - ContentResolver.setMasterSyncAutomatically(isChecked); - onSyncStateUpdated(); - } - }); - mAuthorities = activity.getIntent().getStringArrayExtra(AUTHORITIES_FILTER_KEY); + Bundle args = getArguments(); + if (args != null && args.containsKey(KEY_ACCOUNT_LABEL)) { + getActivity().setTitle(args.getString(KEY_ACCOUNT_LABEL)); + } updateAuthDescriptions(); } @@ -150,30 +149,60 @@ public class ManageAccountsSettings extends AccountPreferenceBase } @Override - public void showDialog(int dialogId) { - if (mDialogFragment != null) { - Log.e(TAG, "Old dialog fragment not null!"); - } - mDialogFragment = new SettingsDialogFragment(this, dialogId); - mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + MenuItem syncNow = menu.add(0, MENU_SYNC_NOW_ID, 0, + getString(R.string.sync_menu_sync_now)) + .setIcon(R.drawable.ic_menu_refresh_holo_dark); + MenuItem syncCancel = menu.add(0, MENU_SYNC_CANCEL_ID, 0, + getString(R.string.sync_menu_sync_cancel)) + .setIcon(com.android.internal.R.drawable.ic_menu_close_clear_cancel); + super.onCreateOptionsMenu(menu, inflater); } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - MenuItem addAccountItem = menu.add(0, MENU_ADD_ACCOUNT, 0, R.string.add_account_label); - addAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM - | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - super.onCreateOptionsMenu(menu, inflater); + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + boolean syncActive = ContentResolver.getCurrentSync() != null; + menu.findItem(MENU_SYNC_NOW_ID).setVisible(!syncActive); + menu.findItem(MENU_SYNC_CANCEL_ID).setVisible(syncActive); } @Override public boolean onOptionsItemSelected(MenuItem item) { - final int itemId = item.getItemId(); - if (itemId == MENU_ADD_ACCOUNT) { - onAddAccountClicked(); + switch (item.getItemId()) { + case MENU_SYNC_NOW_ID: + requestOrCancelSyncForAccounts(true); return true; - } else { - return super.onOptionsItemSelected(item); + case MENU_SYNC_CANCEL_ID: + requestOrCancelSyncForAccounts(false); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void requestOrCancelSyncForAccounts(boolean sync) { + SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes(); + Bundle extras = new Bundle(); + extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + int count = getPreferenceScreen().getPreferenceCount(); + // For each account + for (int i = 0; i < count; i++) { + Preference pref = getPreferenceScreen().getPreference(i); + if (pref instanceof AccountPreference) { + Account account = ((AccountPreference) pref).getAccount(); + // For all available sync authorities, sync those that are enabled for the account + for (int j = 0; j < syncAdapters.length; j++) { + SyncAdapterType sa = syncAdapters[j]; + if (syncAdapters[j].accountType.equals(mAccountType) + && ContentResolver.getSyncAutomatically(account, sa.authority)) { + if (sync) { + ContentResolver.requestSync(account, sa.authority, extras); + } else { + ContentResolver.cancelSync(account, sa.authority); + } + } + } + } } } @@ -181,15 +210,12 @@ public class ManageAccountsSettings extends AccountPreferenceBase protected void onSyncStateUpdated() { // Catch any delayed delivery of update messages if (getActivity() == null) return; - // Set background connection state - if (mAutoSyncSwitch != null) { - mAutoSyncSwitch.setChecked(ContentResolver.getMasterSyncAutomatically()); - } // iterate over all the preferences, setting the state properly for each SyncInfo currentSync = ContentResolver.getCurrentSync(); boolean anySyncFailed = false; // true if sync on any account failed + Date date = new Date(); // only track userfacing sync adapters when deciding if account is synced or not final SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes(); @@ -209,8 +235,10 @@ public class ManageAccountsSettings extends AccountPreferenceBase AccountPreference accountPref = (AccountPreference) pref; Account account = accountPref.getAccount(); int syncCount = 0; + long lastSuccessTime = 0; boolean syncIsFailing = false; final ArrayList<String> authorities = accountPref.getAuthorities(); + boolean syncingNow = false; if (authorities != null) { for (String authority : authorities) { SyncStatusInfo status = ContentResolver.getSyncStatus(account, authority); @@ -231,6 +259,10 @@ public class ManageAccountsSettings extends AccountPreferenceBase syncIsFailing = true; anySyncFailed = true; } + syncingNow |= activelySyncing; + if (status != null && lastSuccessTime < status.lastSuccessTime) { + lastSuccessTime = status.lastSuccessTime; + } syncCount += syncEnabled && userFacing.contains(authority) ? 1 : 0; } } else { @@ -238,15 +270,26 @@ public class ManageAccountsSettings extends AccountPreferenceBase Log.v(TAG, "no syncadapters found for " + account); } } - int syncStatus = AccountPreference.SYNC_DISABLED; if (syncIsFailing) { - syncStatus = AccountPreference.SYNC_ERROR; + accountPref.setSyncStatus(AccountPreference.SYNC_ERROR); } else if (syncCount == 0) { - syncStatus = AccountPreference.SYNC_DISABLED; + accountPref.setSyncStatus(AccountPreference.SYNC_DISABLED); } else if (syncCount > 0) { - syncStatus = AccountPreference.SYNC_ENABLED; + if (syncingNow) { + accountPref.setSyncStatus(AccountPreference.SYNC_IN_PROGRESS); + } else { + accountPref.setSyncStatus(AccountPreference.SYNC_ENABLED); + if (lastSuccessTime > 0) { + accountPref.setSyncStatus(AccountPreference.SYNC_ENABLED); + date.setTime(lastSuccessTime); + final String timeString = formatSyncDate(date); + accountPref.setSummary(getResources().getString( + R.string.last_synced, timeString)); + } + } + } else { + accountPref.setSyncStatus(AccountPreference.SYNC_DISABLED); } - accountPref.setSyncStatus(syncStatus); } mErrorInfoView.setVisibility(anySyncFailed ? View.VISIBLE : View.GONE); @@ -256,8 +299,11 @@ public class ManageAccountsSettings extends AccountPreferenceBase public void onAccountsUpdated(Account[] accounts) { if (getActivity() == null) return; getPreferenceScreen().removeAll(); + addPreferencesFromResource(R.xml.manage_accounts_settings); for (int i = 0, n = accounts.length; i < n; i++) { final Account account = accounts[i]; + // If an account type is specified for this screen, skip other types + if (mAccountType != null && !account.type.equals(mAccountType)) continue; final ArrayList<String> auths = getAuthoritiesForAccountType(account.type); boolean showAccount = true; @@ -278,27 +324,45 @@ public class ManageAccountsSettings extends AccountPreferenceBase getPreferenceScreen().addPreference(preference); } } + if (mAccountType != null) { + addAuthenticatorSettings(); + } onSyncStateUpdated(); } - @Override - protected void onAuthDescriptionsUpdated() { - // Update account icons for all account preference items - for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) { - AccountPreference pref = (AccountPreference) getPreferenceScreen().getPreference(i); - pref.setProviderIcon(getDrawableForType(pref.getAccount().type)); - pref.setSummary(getLabelForType(pref.getAccount().type)); + private void addAuthenticatorSettings() { + PreferenceScreen prefs = addPreferencesForType(mAccountType, getPreferenceScreen()); + if (prefs != null) { + updatePreferenceIntents(prefs); } } - public void onAddAccountClicked() { - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra(AUTHORITIES_FILTER_KEY, mAuthorities); - startActivity(intent); + private void updatePreferenceIntents(PreferenceScreen prefs) { + PackageManager pm = getActivity().getPackageManager(); + for (int i = 0; i < prefs.getPreferenceCount();) { + Intent intent = prefs.getPreference(i).getIntent(); + if (intent != null) { + ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (ri == null) { + prefs.removePreference(prefs.getPreference(i)); + continue; + } else { + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); + } + } + i++; + } } @Override - protected int getHelpResource() { - return R.string.help_url_accounts; + protected void onAuthDescriptionsUpdated() { + // Update account icons for all account preference items + for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) { + Preference pref = getPreferenceScreen().getPreference(i); + if (pref instanceof AccountPreference) { + AccountPreference accPref = (AccountPreference) pref; + accPref.setSummary(getLabelForType(accPref.getAccount().type)); + } + } } } |