/* 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);
}
}