backout 91e7ba697b14 (Bug 1001309) for test failures. r=backout

This commit is contained in:
Wes Johnston 2014-07-17 09:10:43 -07:00
parent f200d0a848
commit 300e4ef498
23 changed files with 204 additions and 698 deletions

View File

@ -11,11 +11,9 @@ import java.lang.Class;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
@ -54,7 +52,6 @@ import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.GeckoMenuItem;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.prompts.PromptListItem;
import org.mozilla.gecko.sync.setup.SyncAccounts;
@ -70,7 +67,6 @@ import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.MenuUtils;
import org.mozilla.gecko.util.PrefUtils;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
@ -2410,11 +2406,9 @@ public class BrowserApp extends GeckoApp
MenuItem enterGuestMode = aMenu.findItem(R.id.new_guest_session);
MenuItem exitGuestMode = aMenu.findItem(R.id.exit_guest_session);
// Only show the "Quit" menu item on pre-ICS, television devices, or if the user has explicitly enabled the clear on shutdown pref.
// Only show the "Quit" menu item on pre-ICS or television devices.
// In ICS+, it's easy to kill an app through the task switcher.
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
final Set<String> clearItems = PrefUtils.getStringSet(prefs, ClearOnShutdownPref.PREF, new HashSet<String>());
aMenu.findItem(R.id.quit).setVisible(clearItems.size() > 0 || Build.VERSION.SDK_INT < 14 || HardwareUtils.isTelevision());
aMenu.findItem(R.id.quit).setVisible(Build.VERSION.SDK_INT < 14 || HardwareUtils.isTelevision());
if (tab == null || tab.getURL() == null) {
bookmark.setEnabled(false);

View File

@ -18,7 +18,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@ -47,7 +46,6 @@ import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.GeckoMenuInflater;
import org.mozilla.gecko.menu.MenuPanel;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.updater.UpdateService;
@ -59,7 +57,6 @@ import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.PrefUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.webapp.EventListener;
import org.mozilla.gecko.webapp.UninstallListener;
@ -466,23 +463,10 @@ public abstract class GeckoApp
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.quit) {
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.GeckoRunning, GeckoThread.LaunchState.GeckoExiting)) {
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
final Set<String> clearSet = PrefUtils.getStringSet(prefs, ClearOnShutdownPref.PREF, new HashSet<String>());
final JSONObject clearObj = new JSONObject();
for (String clear : clearSet) {
try {
clearObj.put(clear, true);
} catch(JSONException ex) {
Log.i(LOGTAG, "Error adding clear object " + clear);
}
}
GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", clearObj.toString()));
GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", null));
} else {
GeckoAppShell.systemExit();
}
return true;
}
@ -612,7 +596,6 @@ public abstract class GeckoApp
} else if ("Sanitize:ClearHistory".equals(event)) {
handleClearHistory();
callback.sendSuccess(true);
} else if ("Session:StatePurged".equals(event)) {
onStatePurged();

View File

@ -145,11 +145,7 @@
<!ENTITY pref_char_encoding "Character encoding">
<!ENTITY pref_char_encoding_on "Show menu">
<!ENTITY pref_char_encoding_off "Don\'t show menu">
<!ENTITY pref_clear_private_data2 "Clear now">
<!ENTITY pref_clear_private_data_category "Clear private data">
<!ENTITY pref_clear_on_exit_title "Always clear when quitting">
<!ENTITY pref_clear_on_exit_summary "&brandShortName; will automatically clear your data whenever you select &quot;Quit&quot; from the main menu">
<!ENTITY pref_clear_on_exit_dialog_title "Select which data to clear">
<!ENTITY pref_clear_private_data "Clear private data">
<!ENTITY pref_plugins "Plugins">
<!ENTITY pref_plugins_enabled "Enabled">
<!ENTITY pref_plugins_tap_to_play "Tap to play">

View File

@ -71,7 +71,6 @@ gujar.sources += [
'util/NativeJSContainer.java',
'util/NativeJSObject.java',
'util/NonEvictingLruCache.java',
'util/PrefUtils.java',
'util/ProxySelector.java',
'util/RawResource.java',
'util/StringUtils.java',
@ -335,18 +334,15 @@ gbjar.sources += [
'preferences/AlignRightLinkPreference.java',
'preferences/AndroidImport.java',
'preferences/AndroidImportPreference.java',
'preferences/ClearOnShutdownPref.java',
'preferences/CustomListCategory.java',
'preferences/CustomListPreference.java',
'preferences/FontSizePreference.java',
'preferences/GeckoPreferenceFragment.java',
'preferences/GeckoPreferences.java',
'preferences/LinkPreference.java',
'preferences/ListCheckboxPreference.java',
'preferences/LocaleListPreference.java',
'preferences/ModifiableHintPreference.java',
'preferences/MultiChoicePreference.java',
'preferences/MultiPrefMultiChoicePreference.java',
'preferences/PanelsPreference.java',
'preferences/PanelsPreferenceCategory.java',
'preferences/PrivateDataPreference.java',

View File

@ -8,14 +8,12 @@ package org.mozilla.gecko.preferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.ThreadUtils;
import java.util.Set;
import android.app.ProgressDialog;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
class AndroidImportPreference extends MultiPrefMultiChoicePreference {
class AndroidImportPreference extends MultiChoicePreference {
static final private String LOGTAG = "AndroidImport";
private static final String PREF_KEY_PREFIX = "import_android.data.";
private Context mContext;
@ -35,15 +33,19 @@ class AndroidImportPreference extends MultiPrefMultiChoicePreference {
boolean bookmarksChecked = false;
boolean historyChecked = false;
Set<String> values = getValues();
CharSequence keys[] = getEntryKeys();
boolean values[] = getValues();
for (String value : values) {
// Import checkbox values are stored in Android prefs to
for (int i = 0; i < keys.length; i++) {
// Privacy pref checkbox values are stored in Android prefs to
// remember their check states. The key names are import_android.data.X
String key = value.substring(PREF_KEY_PREFIX.length());
if ("bookmarks".equals(key)) {
String key = keys[i].toString().substring(PREF_KEY_PREFIX.length());
boolean value = values[i];
if (key.equals("bookmarks") && value) {
bookmarksChecked = true;
} else if ("history".equals(key)) {
}
if (key.equals("history") && value) {
historyChecked = true;
}
}

View File

@ -1,36 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.preferences;
import java.util.HashSet;
import java.util.Set;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.util.PrefUtils;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.Preference;
public class ClearOnShutdownPref implements GeckoPreferences.PrefHandler {
public static final String PREF = GeckoPreferences.NON_PREF_PREFIX + "history.clear_on_exit";
@Override
public void setupPref(Context context, Preference pref) {
// The pref is initialized asynchronously. Read the pref explicitly
// here to make sure we have the data.
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
final Set<String> clearItems = PrefUtils.getStringSet(prefs, PREF, new HashSet<String>());
((ListCheckboxPreference) pref).setChecked(clearItems.size() > 0);
}
@Override
@SuppressWarnings("unchecked")
public void onChange(Context context, Preference pref, Object newValue) {
final Set<String> vals = (Set<String>) newValue;
((ListCheckboxPreference) pref).setChecked(vals.size() > 0);
}
}

View File

@ -6,10 +6,8 @@
package org.mozilla.gecko.preferences;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants;
@ -94,7 +92,7 @@ OnSharedPreferenceChangeListener
// devices.
private static final boolean NO_TRANSITIONS = HardwareUtils.IS_KINDLE_DEVICE;
public static final String NON_PREF_PREFIX = "android.not_a_preference.";
private static final String NON_PREF_PREFIX = "android.not_a_preference.";
public static final String INTENT_EXTRA_RESOURCES = "resource";
public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled";
@ -729,9 +727,6 @@ OnSharedPreferenceChangeListener
return true;
}
});
} else if (handlers.containsKey(key)) {
PrefHandler handler = handlers.get(key);
handler.setupPref(this, pref);
}
// Some Preference UI elements are not actually preferences,
@ -1001,20 +996,9 @@ OnSharedPreferenceChangeListener
}
}
public interface PrefHandler {
public void setupPref(Context context, Preference pref);
public void onChange(Context context, Preference pref, Object newValue);
}
@SuppressWarnings("serial")
private Map<String, PrefHandler> handlers = new HashMap<String, PrefHandler>() {{
put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref());
}};
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final String prefName = preference.getKey();
Log.i(LOGTAG, "Changed " + prefName + " = " + newValue);
if (PREFS_MP_ENABLED.equals(prefName)) {
showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
@ -1046,9 +1030,6 @@ OnSharedPreferenceChangeListener
} else if (PREFS_GEO_REPORTING.equals(prefName)) {
// Translate boolean value to int for geo reporting pref.
newValue = ((Boolean) newValue) ? 1 : 0;
} else if (handlers.containsKey(prefName)) {
PrefHandler handler = handlers.get(prefName);
handler.onChange(this, preference, newValue);
}
// Send Gecko-side pref changes to Gecko

View File

@ -1,58 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.preferences;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import org.mozilla.gecko.R;
/**
* This preference shows a checkbox on its left hand side, but will show a menu when clicked.
* Its used for preferences like "Clear on Exit" that have a boolean on-off state, but that represent
* multiple boolean options inside.
**/
class ListCheckboxPreference extends MultiChoicePreference implements Checkable {
private static final String LOGTAG = "GeckoListCheckboxPreference";
private boolean checked;
public ListCheckboxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.preference_checkbox);
}
@Override
public boolean isChecked() {
return checked;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
View checkboxView = view.findViewById(R.id.checkbox);
if (checkboxView != null && checkboxView instanceof Checkable) {
((Checkable) checkboxView).setChecked(checked);
}
}
@Override
public void setChecked(boolean checked) {
boolean changed = checked != this.checked;
this.checked = checked;
if (changed) {
notifyDependencyChange(shouldDisableDependents());
notifyChanged();
}
}
@Override
public void toggle() {
checked = !checked;
}
}

View File

@ -7,26 +7,23 @@ package org.mozilla.gecko.preferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.util.PrefUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.content.SharedPreferences;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.widget.Button;
import java.util.HashSet;
import java.util.Set;
class MultiChoicePreference extends DialogPreference implements DialogInterface.OnMultiChoiceClickListener {
class MultiChoicePreference extends DialogPreference {
private static final String LOGTAG = "GeckoMultiChoicePreference";
private boolean mValues[];
private boolean mPrevValues[];
private CharSequence mEntryValues[];
private CharSequence mEntryKeys[];
private CharSequence mEntries[];
private CharSequence mInitialValues[];
@ -35,7 +32,7 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiChoicePreference);
mEntries = a.getTextArray(R.styleable.MultiChoicePreference_entries);
mEntryValues = a.getTextArray(R.styleable.MultiChoicePreference_entryValues);
mEntryKeys = a.getTextArray(R.styleable.MultiChoicePreference_entryKeys);
mInitialValues = a.getTextArray(R.styleable.MultiChoicePreference_initialValues);
a.recycle();
@ -51,9 +48,9 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
* shown in subsequent dialogs.
* <p>
* Each entry must have a corresponding index in
* {@link #setEntryValues(CharSequence[])} and
* {@link #setEntryKeys(CharSequence[])} and
* {@link #setInitialValues(CharSequence[])}.
*
*
* @param entries The entries.
*/
public void setEntries(CharSequence[] entries) {
@ -68,22 +65,20 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
}
/**
* Sets the preference values for preferences shown in the list.
* Sets the preference keys for preferences shown in the list.
*
* @param entryValues The entry values.
* @param entryKeys The entry keys.
*/
public void setEntryValues(CharSequence[] entryValues) {
mEntryValues = entryValues.clone();
public void setEntryKeys(CharSequence[] entryKeys) {
mEntryKeys = entryKeys.clone();
loadPersistedValues();
}
/**
* Entry values define a separate pref for each row in the dialog.
*
* @param entryValuesResId The entryValues array as a resource.
* @param entryKeysResId The entryKeys array as a resource.
*/
public void setEntryValues(int entryValuesResId) {
setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
public void setEntryKeys(int entryKeysResId) {
setEntryKeys(getContext().getResources().getTextArray(entryKeysResId));
}
/**
@ -116,12 +111,12 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
}
/**
* The list of values corresponding to each preference.
* The list of keys corresponding to each preference.
*
* @return The array of values.
* @return The array of keys.
*/
public CharSequence[] getEntryValues() {
return mEntryValues.clone();
public CharSequence[] getEntryKeys() {
return mEntryKeys.clone();
}
/**
@ -134,50 +129,46 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
return mInitialValues.clone();
}
public void setValue(final int i, final boolean value) {
mValues[i] = value;
mPrevValues = mValues.clone();
}
/**
* The list of values for each preference. These values are updated after
* the dialog has been displayed.
*
* @return The array of values.
*/
public Set<String> getValues() {
final Set<String> values = new HashSet<String>();
if (mValues == null) {
return values;
}
for (int i = 0; i < mValues.length; i++) {
if (mValues[i]) {
values.add(mEntryValues[i].toString());
}
}
return values;
}
@Override
public void onClick(DialogInterface dialog, int which, boolean val) {
public boolean[] getValues() {
return mValues.clone();
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
if (mEntries == null || mInitialValues == null || mEntryValues == null) {
if (mEntries == null || mEntryKeys == null || mInitialValues == null) {
throw new IllegalStateException(
"MultiChoicePreference requires entries, entryValues, and initialValues arrays.");
"MultiChoicePreference requires entries, entryKeys, and initialValues arrays.");
}
if (mEntries.length != mEntryValues.length || mEntries.length != mInitialValues.length) {
if (mEntries.length != mEntryKeys.length || mEntryKeys.length != mInitialValues.length) {
throw new IllegalStateException(
"MultiChoicePreference entries, entryValues, and initialValues arrays must be the same length");
"MultiChoicePreference entries, entryKeys, and initialValues arrays must be the same length");
}
builder.setMultiChoiceItems(mEntries, mValues, this);
builder.setMultiChoiceItems(mEntries, mValues, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean val) {
// mValues is automatically updated when checkboxes are clicked
// enable positive button only if at least one item is checked
boolean enabled = false;
for (int i = 0; i < mValues.length; i++) {
if (mValues[i]) {
enabled = true;
break;
}
}
Button button = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
if (button.isEnabled() != enabled)
button.setEnabled(enabled);
}
});
}
@Override
@ -196,44 +187,37 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
mPrevValues = mValues.clone();
}
if (!callChangeListener(getValues())) {
return;
}
persist();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < mEntryKeys.length; i++) {
String key = mEntryKeys[i].toString();
persistBoolean(key, mValues[i]);
}
}
});
}
/* Persists the current data stored by this pref to SharedPreferences. */
public boolean persist() {
protected boolean persistBoolean(String key, boolean value) {
if (isPersistent()) {
final SharedPreferences.Editor edit = GeckoSharedPrefs.forProfile(getContext()).edit();
final boolean res = persist(edit);
edit.commit();
return res;
}
return false;
}
/* Internal persist method. Take an edit so that multiple prefs can be persisted in a single commit. */
protected boolean persist(SharedPreferences.Editor edit) {
if (isPersistent()) {
Set<String> vals = getValues();
PrefUtils.putStringSet(edit, getKey(), vals);
if (value == getPersistedBoolean(!value)) {
// It's already there, so the same as persisting
return true;
}
GeckoSharedPrefs.forApp(getContext())
.edit().putBoolean(key, value).commit();
return true;
}
return false;
}
/* Returns a list of EntryValues that are currently enabled. */
public Set<String> getPersistedStrings(Set<String> defaultVal) {
if (!isPersistent()) {
return defaultVal;
}
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getContext());
return PrefUtils.getStringSet(prefs, getKey(), defaultVal);
protected boolean getPersistedBoolean(String key, boolean defaultReturnValue) {
if (!isPersistent())
return defaultReturnValue;
return GeckoSharedPrefs.forApp(getContext())
.getBoolean(key, defaultReturnValue);
}
/**
@ -241,29 +225,25 @@ class MultiChoicePreference extends DialogPreference implements DialogInterface.
* aren't persistent or haven't yet been stored, they will be set to their
* initial values.
*/
protected void loadPersistedValues() {
final int entryCount = mInitialValues.length;
mValues = new boolean[entryCount];
private void loadPersistedValues() {
if (mEntryKeys == null || mInitialValues == null)
return;
if (entryCount != mEntries.length || entryCount != mEntryValues.length) {
final int entryCount = mEntryKeys.length;
if (entryCount != mEntries.length || entryCount != mInitialValues.length) {
throw new IllegalStateException(
"MultiChoicePreference entryValues and initialValues arrays must be the same length");
"MultiChoicePreference entryKeys and initialValues arrays must be the same length");
}
mValues = new boolean[entryCount];
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final Set<String> stringVals = getPersistedStrings(null);
for (int i = 0; i < entryCount; i++) {
if (stringVals != null) {
mValues[i] = stringVals.contains(mEntryValues[i]);
} else {
final boolean defaultVal = mInitialValues[i].equals("true");
mValues[i] = defaultVal;
}
String key = mEntryKeys[i].toString();
boolean initialValue = mInitialValues[i].equals("true");
mValues[i] = getPersistedBoolean(key, initialValue);
}
mPrevValues = mValues.clone();
}
});

View File

@ -1,116 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* 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.preferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.content.SharedPreferences;
import android.widget.Button;
import android.util.AttributeSet;
import android.util.Log;
import java.util.Set;
/* Provides backwards compatibility for some old multi-choice pref types used by Gecko.
* This will import the old data from the old prefs the first time it is run.
*/
class MultiPrefMultiChoicePreference extends MultiChoicePreference {
private static final String LOGTAG = "GeckoMultiPrefPreference";
private static final String IMPORT_SUFFIX = "_imported_";
private final CharSequence[] keys;
public MultiPrefMultiChoicePreference(Context context, AttributeSet attrs) {
super(context, attrs);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiPrefMultiChoicePreference);
keys = a.getTextArray(R.styleable.MultiPrefMultiChoicePreference_entryKeys);
a.recycle();
loadPersistedValues();
}
// Helper method for reading a boolean pref.
private boolean getPersistedBoolean(SharedPreferences prefs, String key, boolean defaultReturnValue) {
if (!isPersistent()) {
return defaultReturnValue;
}
return prefs.getBoolean(key, defaultReturnValue);
}
// Overridden to do a one time import for the old preference type to the new one.
@Override
protected synchronized void loadPersistedValues() {
// This will load the new pref if it exists.
super.loadPersistedValues();
// First check if we've already done the import the old data. If so, nothing to load.
final SharedPreferences prefs = GeckoSharedPrefs.forApp(getContext());
final boolean imported = getPersistedBoolean(prefs, getKey() + IMPORT_SUFFIX, false);
if (imported) {
return;
}
// Load the data we'll need to find the old style prefs
final CharSequence[] init = getInitialValues();
final CharSequence[] entries = getEntries();
if (keys == null || init == null) {
return;
}
final int entryCount = keys.length;
if (entryCount != entries.length || entryCount != init.length) {
throw new IllegalStateException("MultiChoicePreference entryKeys and initialValues arrays must be the same length");
}
// Now iterate through the entries on a background thread.
final SharedPreferences.Editor edit = prefs.edit();
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
try {
// Use one editor to batch as many changes as we can.
for (int i = 0; i < entryCount; i++) {
String key = keys[i].toString();
boolean initialValue = "true".equals(init[i]);
boolean val = getPersistedBoolean(prefs, key, initialValue);
// Save the pref and remove the old preference.
setValue(i, val);
edit.remove(key);
}
persist(edit);
edit.putBoolean(getKey() + IMPORT_SUFFIX, true);
edit.commit();
} catch(Exception ex) {
Log.i(LOGTAG, "Err", ex);
}
}
});
}
@Override
public void onClick(DialogInterface dialog, int which, boolean val) {
// enable positive button only if at least one item is checked
boolean enabled = false;
final Set<String> values = getValues();
enabled = (values.size() > 0);
final Button button = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
if (button.isEnabled() != enabled) {
button.setEnabled(enabled);
}
}
}

View File

@ -13,13 +13,11 @@ import org.mozilla.gecko.TelemetryContract;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Set;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
class PrivateDataPreference extends MultiPrefMultiChoicePreference {
class PrivateDataPreference extends MultiChoicePreference {
private static final String LOGTAG = "GeckoPrivateDataPreference";
private static final String PREF_KEY_PREFIX = "private.data.";
@ -31,24 +29,25 @@ class PrivateDataPreference extends MultiPrefMultiChoicePreference {
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (!positiveResult) {
if (!positiveResult)
return;
}
Telemetry.sendUIEvent(TelemetryContract.Event.SANITIZE, TelemetryContract.Method.DIALOG, "settings");
final Set<String> values = getValues();
final JSONObject json = new JSONObject();
CharSequence keys[] = getEntryKeys();
boolean values[] = getValues();
JSONObject json = new JSONObject();
for (String value : values) {
for (int i = 0; i < keys.length; i++) {
// Privacy pref checkbox values are stored in Android prefs to
// remember their check states. The key names are private.data.X,
// where X is a string from Gecko sanitization. This prefix is
// removed here so we can send the values to Gecko, which then does
// the sanitization for each key.
final String key = value.substring(PREF_KEY_PREFIX.length());
String key = keys[i].toString().substring(PREF_KEY_PREFIX.length());
boolean value = values[i];
try {
json.put(key, true);
json.put(key, value);
} catch (JSONException e) {
Log.e(LOGTAG, "JSON error", e);
}

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 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.
-->
<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
inside android.R.layout.preference. -->
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="false"
android:clickable="false" />

View File

@ -69,13 +69,9 @@
<item>@string/bookmarks_title</item>
<item>@string/history_title</item>
</string-array>
<string-array name="pref_import_android_defaults">
<item>true</item>
<item>true</item>
</string-array>
<string-array name="pref_import_android_values">
<item>android_import.data.bookmarks</item>
<item>android_import.data.history</item>
<item>true</item>
<item>true</item>
</string-array>
<string-array name="pref_import_android_keys">
<item>android_import.data.bookmarks</item>
@ -91,25 +87,15 @@
<item>@string/pref_private_data_offlineApps</item>
<item>@string/pref_private_data_siteSettings</item>
</string-array>
<string-array name="pref_private_data_defaults">
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
</string-array>
<string-array name="pref_private_data_values">
<item>private.data.history</item>
<item>private.data.downloadFiles</item>
<item>private.data.formdata</item>
<item>private.data.cookies_sessions</item>
<item>private.data.passwords</item>
<item>private.data.cache</item>
<item>private.data.offlineApps</item>
<item>private.data.siteSettings</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
<item>true</item>
</string-array>
<string-array name="pref_private_data_keys">
<item>private.data.history</item>
@ -121,16 +107,6 @@
<item>private.data.offlineApps</item>
<item>private.data.siteSettings</item>
</string-array>
<string-array name="pref_clear_on_exit_defaults">
<item>false</item>
<item>false</item>
<item>false</item>
<item>false</item>
<item>false</item>
<item>false</item>
<item>false</item>
<item>false</item>
</string-array>
<string-array name="pref_restore_entries">
<item>@string/pref_restore_always</item>
<item>@string/pref_restore_quit</item>

View File

@ -84,12 +84,8 @@
<declare-styleable name="MultiChoicePreference">
<attr name="entries" format="string"/>
<attr name="entryValues" format="string"/>
<attr name="initialValues" format="string"/>
</declare-styleable>
<declare-styleable name="MultiPrefMultiChoicePreference">
<attr name="entryKeys" format="string"/>
<attr name="initialValues" format="string"/>
</declare-styleable>
<declare-styleable name="BrowserToolbarCurve">

View File

@ -33,9 +33,8 @@
<org.mozilla.gecko.preferences.AndroidImportPreference
android:key="android.not_a_preference.import_android"
gecko:entries="@array/pref_import_android_entries"
gecko:entryValues="@array/pref_import_android_values"
gecko:initialValues="@array/pref_import_android_defaults"
gecko:entryKeys="@array/pref_import_android_keys"
gecko:initialValues="@array/pref_import_android_values"
android:title="@string/pref_import_android"
android:positiveButtonText="@string/bookmarkhistory_button_import"
android:negativeButtonText="@string/button_cancel"

View File

@ -40,8 +40,8 @@
<org.mozilla.gecko.preferences.AndroidImportPreference
android:key="android.not_a_preference.import_android"
gecko:entries="@array/pref_import_android_entries"
gecko:entryValues="@array/pref_import_android_values"
gecko:initialValues="@array/pref_import_android_defaults"
gecko:entryKeys="@array/pref_import_android_keys"
gecko:initialValues="@array/pref_import_android_values"
android:title="@string/pref_import_android"
android:positiveButtonText="@string/bookmarkhistory_button_import"
android:negativeButtonText="@string/button_cancel"

View File

@ -41,9 +41,8 @@
<org.mozilla.gecko.preferences.AndroidImportPreference
android:key="android.not_a_preference.import_android"
gecko:entries="@array/pref_import_android_entries"
gecko:entryValues="@array/pref_import_android_values"
gecko:initialValues="@array/pref_import_android_defaults"
gecko:entryKeys="@array/pref_import_android_keys"
gecko:initialValues="@array/pref_import_android_values"
android:title="@string/pref_import_android"
android:positiveButtonText="@string/bookmarkhistory_button_import"
android:negativeButtonText="@string/button_cancel"

View File

@ -31,32 +31,14 @@
android:persistent="false" />
<!-- keys prefixed with "android.not_a_preference." are not synced with Gecko -->
<PreferenceCategory android:title="@string/pref_clear_private_data_category">
<org.mozilla.gecko.preferences.PrivateDataPreference
android:key="android.not_a_preference.privacy.clear"
android:title="@string/pref_clear_private_data"
android:persistent="true"
android:positiveButtonText="@string/button_clear_data"
gecko:entries="@array/pref_private_data_entries"
gecko:entryValues="@array/pref_private_data_values"
gecko:entryKeys="@array/pref_private_data_keys"
gecko:initialValues="@array/pref_private_data_defaults" />
<!-- This pref is persisted in both Gecko and Java -->
<org.mozilla.gecko.preferences.ListCheckboxPreference
android:key="android.not_a_preference.history.clear_on_exit"
gecko:entries="@array/pref_private_data_entries"
gecko:entryValues="@array/pref_private_data_values"
gecko:initialValues="@array/pref_clear_on_exit_defaults"
android:title="@string/pref_clear_on_exit_title"
android:summary="@string/pref_clear_on_exit_summary"
android:dialogTitle="@string/pref_clear_on_exit_dialog_title"
android:positiveButtonText="@string/button_set"/>
</PreferenceCategory>
<org.mozilla.gecko.preferences.PrivateDataPreference
android:key="android.not_a_preference.privacy.clear"
android:title="@string/pref_clear_private_data"
android:persistent="true"
android:positiveButtonText="@string/button_clear_data"
gecko:entries="@array/pref_private_data_entries"
gecko:entryKeys="@array/pref_private_data_keys"
gecko:initialValues="@array/pref_private_data_values" />
</PreferenceScreen>

View File

@ -165,11 +165,7 @@
<string name="pref_char_encoding">&pref_char_encoding;</string>
<string name="pref_char_encoding_on">&pref_char_encoding_on;</string>
<string name="pref_char_encoding_off">&pref_char_encoding_off;</string>
<string name="pref_clear_private_data">&pref_clear_private_data2;</string>
<string name="pref_clear_private_data_category">&pref_clear_private_data_category;</string>
<string name="pref_clear_on_exit_title">&pref_clear_on_exit_title;</string>
<string name="pref_clear_on_exit_summary">&pref_clear_on_exit_summary;</string>
<string name="pref_clear_on_exit_dialog_title">&pref_clear_on_exit_dialog_title;</string>
<string name="pref_clear_private_data">&pref_clear_private_data;</string>
<string name="pref_plugins">&pref_plugins;</string>
<string name="pref_plugins_enabled">&pref_plugins_enabled;</string>
<string name="pref_plugins_tap_to_play">&pref_plugins_tap_to_play;</string>

View File

@ -4,15 +4,16 @@
package org.mozilla.gecko.util;
import org.json.JSONArray;
import java.util.UUID;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
public final class JSONUtils {
@ -50,20 +51,4 @@ public final class JSONUtils {
return json;
}
// Handles conversions between a JSONArray and a Set<String>
public static Set<String> parseStringSet(JSONArray json) {
final Set<String> ret = new HashSet<String>();
for (int i = 0; i < json.length(); i++) {
try {
ret.add(json.getString(i));
} catch(JSONException ex) {
Log.i(LOGTAG, "Error parsing json", ex);
}
}
return ret;
}
}

View File

@ -1,72 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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.util;
import android.content.SharedPreferences;
import android.os.Build;
import android.util.Log;
import java.util.HashSet;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
public class PrefUtils {
private static final String LOGTAG = "GeckoPrefUtils";
// Cross version compatible way to get a string set from a pref
public static Set<String> getStringSet(final SharedPreferences prefs,
final String key,
final Set<String> defaultVal) {
if (!prefs.contains(key)) {
return defaultVal;
}
if (Build.VERSION.SDK_INT < 11) {
return getFromJSON(prefs, key);
}
// If this is Android version >= 11, try to use a Set<String>.
try {
return prefs.getStringSet(key, new HashSet<String>());
} catch(ClassCastException ex) {
// A ClassCastException means we've upgraded from a pre-v11 Android to a new one
final Set<String> val = getFromJSON(prefs, key);
SharedPreferences.Editor edit = prefs.edit();
putStringSet(edit, key, val).commit();
return val;
}
}
private static Set<String> getFromJSON(SharedPreferences prefs, String key) {
try {
final String val = prefs.getString(key, "[]");
return JSONUtils.parseStringSet(new JSONArray(val));
} catch(JSONException ex) {
Log.i(LOGTAG, "Unable to parse JSON", ex);
}
return new HashSet<String>();
}
// Cross version compatible way to save a string set to a pref.
// NOTE: The editor that is passed in will not commit the transaction for you. It is up to callers to commit
// when they are done with any other changes to the database.
public static SharedPreferences.Editor putStringSet(final SharedPreferences.Editor edit,
final String key,
final Set<String> vals) {
if (Build.VERSION.SDK_INT < 11) {
final JSONArray json = new JSONArray(vals);
edit.putString(key, json.toString()).commit();
} else {
edit.putStringSet(key, vals).commit();
}
return edit;
}
}

View File

@ -1113,7 +1113,7 @@ var BrowserApp = {
aTab.browser.dispatchEvent(evt);
},
quit: function quit(aClear = {}) {
quit: function quit() {
// Figure out if there's at least one other browser window around.
let lastBrowser = true;
let e = Services.wm.getEnumerator("navigator:browser");
@ -1133,10 +1133,8 @@ var BrowserApp = {
Services.obs.notifyObservers(null, "browser-lastwindow-close-granted", null);
}
BrowserApp.sanitize(aClear, function() {
window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
window.close();
});
window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
window.close();
},
saveAsPDF: function saveAsPDF(aBrowser) {
@ -1390,50 +1388,33 @@ var BrowserApp = {
}
},
sanitize: function (aItems, callback) {
if (!aItems) {
return;
}
sanitize: function (aItems) {
let json = JSON.parse(aItems);
let success = true;
for (let key in aItems) {
if (!aItems[key])
for (let key in json) {
if (!json[key])
continue;
key = key.replace("private.data.", "");
var promises = [];
switch (key) {
case "cookies_sessions":
promises.push(Sanitizer.clearItem("cookies"));
promises.push(Sanitizer.clearItem("sessions"));
break;
default:
promises.push(Sanitizer.clearItem(key));
try {
switch (key) {
case "cookies_sessions":
Sanitizer.clearItem("cookies");
Sanitizer.clearItem("sessions");
break;
default:
Sanitizer.clearItem(key);
}
} catch (e) {
dump("sanitize error: " + e);
success = false;
}
}
Promise.all(promises).then(function() {
sendMessageToJava({
type: "Sanitize:Finished",
success: true
});
if (callback) {
callback();
}
}).catch(function(err) {
sendMessageToJava({
type: "Sanitize:Finished",
error: err,
success: false
});
if (callback) {
callback();
}
})
sendMessageToJava({
type: "Sanitize:Finished",
success: success
});
},
getFocusedInput: function(aBrowser, aOnlyInputElements = false) {
@ -1620,8 +1601,7 @@ var BrowserApp = {
break;
case "Browser:Quit":
Services.console.logStringMessage(aData);
this.quit(JSON.parse(aData));
this.quit();
break;
case "SaveAs:PDF":
@ -1639,7 +1619,7 @@ var BrowserApp = {
break;
case "Sanitize:ClearData":
this.sanitize(JSON.parse(aData));
this.sanitize(aData);
break;
case "FullScreen:Exit":

View File

@ -64,20 +64,16 @@ Sanitizer.prototype = {
cache: {
clear: function ()
{
return new Promise(function(resolve, reject) {
var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
try {
cache.clear();
} catch(er) {}
var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
try {
cache.clear();
} catch(er) {}
let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.getImgCacheForDocument(null);
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch(er) {}
resolve();
});
let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.getImgCacheForDocument(null);
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch(er) {}
},
get canClear()
@ -89,10 +85,7 @@ Sanitizer.prototype = {
cookies: {
clear: function ()
{
return new Promise(function(resolve, reject) {
Services.cookies.removeAll();
resolve();
});
Services.cookies.removeAll();
},
get canClear()
@ -104,24 +97,20 @@ Sanitizer.prototype = {
siteSettings: {
clear: function ()
{
return new Promise(function(resolve, reject) {
// Clear site-specific permissions like "Allow this site to open popups"
Services.perms.removeAll();
// Clear site-specific permissions like "Allow this site to open popups"
Services.perms.removeAll();
// Clear site-specific settings like page-zoom level
Cc["@mozilla.org/content-pref/service;1"]
.getService(Ci.nsIContentPrefService2)
.removeAllDomains(null);
// Clear site-specific settings like page-zoom level
Cc["@mozilla.org/content-pref/service;1"]
.getService(Ci.nsIContentPrefService2)
.removeAllDomains(null);
// Clear "Never remember passwords for this site", which is not handled by
// the permission manager
var hosts = Services.logins.getAllDisabledHosts({})
for (var host of hosts) {
Services.logins.setLoginSavingEnabled(host, true);
}
resolve();
});
// Clear "Never remember passwords for this site", which is not handled by
// the permission manager
var hosts = Services.logins.getAllDisabledHosts({})
for (var host of hosts) {
Services.logins.setLoginSavingEnabled(host, true);
}
},
get canClear()
@ -133,15 +122,11 @@ Sanitizer.prototype = {
offlineApps: {
clear: function ()
{
return new Promise(function(resolve, reject) {
var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null);
try {
appCacheStorage.asyncEvictStorage(null);
} catch(er) {}
resolve();
});
var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null);
try {
appCacheStorage.asyncEvictStorage(null);
} catch(er) {}
},
get canClear()
@ -153,21 +138,17 @@ Sanitizer.prototype = {
history: {
clear: function ()
{
return new Promise(function(resolve, reject) {
sendMessageToJava({ type: "Sanitize:ClearHistory" }, function() {
try {
Services.obs.notifyObservers(null, "browser:purge-session-history", "");
}
catch (e) { }
sendMessageToJava({ type: "Sanitize:ClearHistory" });
try {
var predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
predictor.reset();
} catch (e) { }
try {
Services.obs.notifyObservers(null, "browser:purge-session-history", "");
}
catch (e) { }
resolve();
});
});
try {
var predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
predictor.reset();
} catch (e) { }
},
get canClear()
@ -181,10 +162,7 @@ Sanitizer.prototype = {
formdata: {
clear: function ()
{
return new Promise(function(resolve, reject) {
FormHistory.update({ op: "remove" });
resolve();
});
FormHistory.update({ op: "remove" });
},
canClear: function (aCallback)
@ -202,18 +180,15 @@ Sanitizer.prototype = {
downloadFiles: {
clear: function ()
{
return new Promise(function(resolve, reject) {
downloads.iterate(function (dl) {
// Delete the downloaded files themselves
let f = dl.targetFile;
if (f.exists()) {
f.remove(false);
}
downloads.iterate(function (dl) {
// Delete the downloaded files themselves
let f = dl.targetFile;
if (f.exists()) {
f.remove(false);
}
// Also delete downloads from history
dl.remove();
});
resolve();
// Also delete downloads from history
dl.remove();
});
},
@ -226,10 +201,7 @@ Sanitizer.prototype = {
passwords: {
clear: function ()
{
return new Promise(function(resolve, reject) {
Services.logins.removeAllLogins();
resolve();
});
Services.logins.removeAllLogins();
},
get canClear()
@ -242,16 +214,12 @@ Sanitizer.prototype = {
sessions: {
clear: function ()
{
return new Promise(function(resolve, reject) {
// clear all auth tokens
var sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing);
sdr.logoutAndTeardown();
// clear all auth tokens
var sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing);
sdr.logoutAndTeardown();
// clear FTP and plain HTTP auth sessions
Services.obs.notifyObservers(null, "net:clear-active-logins", null);
resolve();
});
// clear FTP and plain HTTP auth sessions
Services.obs.notifyObservers(null, "net:clear-active-logins", null);
},
get canClear()