/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.sync.config.activities; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.mozilla.gecko.R; import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.SyncConfiguration; import org.mozilla.gecko.sync.ThreadPool; import org.mozilla.gecko.sync.setup.SyncAccounts; import org.mozilla.gecko.sync.syncadapter.SyncAdapter; import android.accounts.Account; import android.accounts.AccountManager; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.SharedPreferences; import android.os.Bundle; import android.widget.ListView; import android.widget.Toast; /** * Provides a user-facing interface for selecting engines to sync. This activity * can be launched from the Sync Settings preferences screen, and will save the * selected engines to the * <code>SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC</code> pref. * * On launch, it displays the engines stored in the saved pref if it exists, or * <code>SyncConfiguration.enabledEngineNames()</code> if it doesn't, defaulting * to <code>SyncConfiguration.validEngineNames()</code> if neither exists. * * During a sync, the * <code>SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC</code> pref will * be cleared after the engine changes are applied to meta/global. */ public class SelectEnginesActivity extends Activity implements DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener { public final static String LOG_TAG = "SelectEnginesAct"; protected AccountManager mAccountManager; protected Context mContext; // Collections names corresponding to displayed (localized) engine options. final String[] _collectionsNames = new String[] { "bookmarks", "passwords", "history", "tabs" }; // Engine names localized for display in Sync Settings. protected String[] _options; // Selection state of engines corresponding to _options array. final boolean[] _selections = new boolean[_collectionsNames.length]; protected Account account; protected SharedPreferences accountPrefs; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = getApplicationContext(); mAccountManager = AccountManager.get(mContext); _options = new String[] { getString(R.string.sync_configure_engines_title_bookmarks), getString(R.string.sync_configure_engines_title_passwords), getString(R.string.sync_configure_engines_title_history), getString(R.string.sync_configure_engines_title_tabs) }; // Fetch account prefs for configuring engines. ThreadPool.run(new Runnable() { @Override public void run() { Account[] accounts = SyncAccounts.syncAccounts(mContext); if (accounts.length == 0) { Logger.error(LOG_TAG, "Failed to get account!"); finish(); return; } else { // Only supports one account per type. account = accounts[0]; try { if (accountPrefs == null) { accountPrefs = SyncAccounts.blockingPrefsFromDefaultProfileV0(mContext, mAccountManager, account); } } catch (Exception e) { Logger.error(LOG_TAG, "Failed to get sync account info or shared preferences.", e); finish(); } setSelectionsInArray(getEnginesToSelect(accountPrefs), _selections); } } }); } @Override public void onResume() { super.onResume(); if (accountPrefs != null) { setSelectionsInArray(getEnginesToSelect(accountPrefs), _selections); } AlertDialog dialog = new AlertDialog.Builder(this) .setTitle(R.string.sync_configure_engines_sync_my_title) .setMultiChoiceItems(_options, _selections, this) .setIcon(R.drawable.icon).setPositiveButton(android.R.string.ok, this) .setNegativeButton(android.R.string.cancel, this).create(); dialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { finish(); } }); dialog.show(); } private Set<String> getEnginesFromPrefs(SharedPreferences syncPrefs) { Set<String> engines = SyncConfiguration.getEnabledEngineNames(syncPrefs); if (engines == null) { engines = SyncConfiguration.validEngineNames(); } return engines; } /** * Fetches the engine names that should be displayed as selected for syncing. * Check first for selected engines set by this activity, then the enabled * engines, and finally default to the set of valid engine names for Android * Sync if neither exists. * * @param syncPrefs * <code>SharedPreferences</code> of Account being modified. * @return Set<String> of engine names to display as selected. Should never be * null. */ private Set<String> getEnginesToSelect(SharedPreferences syncPrefs) { Set<String> engines = getEnginesFromPrefs(syncPrefs); Map<String, Boolean> engineSelections = SyncConfiguration.getUserSelectedEngines(syncPrefs); if (engineSelections != null) { for (Entry<String, Boolean> pair : engineSelections.entrySet()) { if (pair.getValue()) { engines.add(pair.getKey()); } else { engines.remove(pair.getKey()); } } } return engines; } public void setSelectionsInArray(Set<String> selected, boolean[] array) { for (int i = 0; i < _collectionsNames.length; i++) { array[i] = selected.contains(_collectionsNames[i]); } } @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { Logger.debug(LOG_TAG, "Saving selected engines."); saveSelections(); setResult(RESULT_OK); Toast.makeText(this, R.string.sync_notification_savedprefs, Toast.LENGTH_SHORT).show(); } else { setResult(RESULT_CANCELED); } finish(); } @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { // Display multi-selection clicks in UI. _selections[which] = isChecked; ListView selectionsList = ((AlertDialog) dialog).getListView(); selectionsList.setItemChecked(which, isChecked); } /** * Persists engine selection state to SharedPreferences if it has changed. * * @return true if changed, false otherwise. */ private void saveSelections() { boolean[] origSelections = new boolean[_options.length]; setSelectionsInArray(getEnginesFromPrefs(accountPrefs), origSelections); Map<String, Boolean> engineSelections = new HashMap<String, Boolean>(); for (int i = 0; i < _selections.length; i++) { if (_selections[i] != origSelections[i]) { engineSelections.put(_collectionsNames[i], _selections[i]); } } // No GlobalSession.config, so store directly to prefs. SyncConfiguration.storeSelectedEnginesToPrefs(accountPrefs, engineSelections); // Request immediate sync. SyncAdapter.requestImmediateSync(account, null); } }