diff options
author | Matt A. Tobin <email@mattatobin.com> | 2019-04-23 15:32:23 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2019-04-23 15:32:23 -0400 |
commit | abe80cc31d5a40ebed743085011fbcda0c1a9a10 (patch) | |
tree | fb3762f06b84745b182af281abb107b95a9fcf01 /mobile/android/base/java/org/mozilla/gecko/preferences | |
parent | 63295d0087eb58a6eb34cad324c4c53d1b220491 (diff) | |
download | UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.gz UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.lz UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.tar.xz UXP-abe80cc31d5a40ebed743085011fbcda0c1a9a10.zip |
Issue #1053 - Drop support Android and remove Fennec - Part 1a: Remove mobile/android
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/preferences')
25 files changed, 0 insertions, 4880 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/AlignRightLinkPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/AlignRightLinkPreference.java deleted file mode 100644 index b68a018f2..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/AlignRightLinkPreference.java +++ /dev/null @@ -1,24 +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 android.content.Context; -import android.util.AttributeSet; - -class AlignRightLinkPreference extends LinkPreference { - - public AlignRightLinkPreference(Context context, AttributeSet attrs) { - super(context, attrs); - setLayoutResource(R.layout.preference_rightalign_icon); - } - - public AlignRightLinkPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - setLayoutResource(R.layout.preference_rightalign_icon); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImport.java b/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImport.java deleted file mode 100644 index bb71ce78b..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImport.java +++ /dev/null @@ -1,230 +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.ContentValues; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Build; -import org.mozilla.gecko.GeckoProfile; -import org.mozilla.gecko.db.BrowserContract; -import org.mozilla.gecko.db.BrowserContract.Bookmarks; -import org.mozilla.gecko.db.LocalBrowserDB; -import org.mozilla.gecko.icons.IconResponse; -import org.mozilla.gecko.icons.IconsHelper; -import org.mozilla.gecko.icons.storage.DiskStorage; - -import android.content.ContentProviderOperation; -import android.content.ContentResolver; -import android.content.Context; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.net.Uri; -import android.os.RemoteException; -import android.provider.BaseColumns; -import android.text.TextUtils; -import android.util.Log; - -import java.util.ArrayList; - -public class AndroidImport implements Runnable { - /** - * The Android M SDK removed several fields and methods from android.provider.Browser. This class is used as a - * replacement to support building with the new SDK but at the same time still use these fields on lower Android - * versions. - */ - private static class LegacyBrowserProvider { - public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks"); - - // Incomplete: This are just the fields we currently use in our code base - public static class BookmarkColumns implements BaseColumns { - public static final String URL = "url"; - public static final String VISITS = "visits"; - public static final String DATE = "date"; - public static final String BOOKMARK = "bookmark"; - public static final String TITLE = "title"; - public static final String CREATED = "created"; - public static final String FAVICON = "favicon"; - } - } - - public static final Uri SAMSUNG_BOOKMARKS_URI = Uri.parse("content://com.sec.android.app.sbrowser.browser/bookmarks"); - public static final Uri SAMSUNG_HISTORY_URI = Uri.parse("content://com.sec.android.app.sbrowser.browser/history"); - public static final String SAMSUNG_MANUFACTURER = "samsung"; - - private static final String LOGTAG = "AndroidImport"; - private final Context mContext; - private final Runnable mOnDoneRunnable; - private final ArrayList<ContentProviderOperation> mOperations; - private final ContentResolver mCr; - private final LocalBrowserDB mDB; - private final boolean mImportBookmarks; - private final boolean mImportHistory; - - public AndroidImport(Context context, Runnable onDoneRunnable, - boolean doBookmarks, boolean doHistory) { - mContext = context; - mOnDoneRunnable = onDoneRunnable; - mOperations = new ArrayList<ContentProviderOperation>(); - mCr = mContext.getContentResolver(); - mDB = new LocalBrowserDB(GeckoProfile.get(context).getName()); - mImportBookmarks = doBookmarks; - mImportHistory = doHistory; - } - - public void mergeBookmarks() { - Cursor cursor = null; - try { - cursor = query(LegacyBrowserProvider.BOOKMARKS_URI, - SAMSUNG_BOOKMARKS_URI, - LegacyBrowserProvider.BookmarkColumns.BOOKMARK + " = 1"); - - if (cursor != null) { - final int faviconCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.FAVICON); - final int titleCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.TITLE); - final int urlCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.URL); - // http://code.google.com/p/android/issues/detail?id=17969 - final int createCol = cursor.getColumnIndex(LegacyBrowserProvider.BookmarkColumns.CREATED); - - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - String url = cursor.getString(urlCol); - String title = cursor.getString(titleCol); - long created; - if (createCol >= 0) { - created = cursor.getLong(createCol); - } else { - created = System.currentTimeMillis(); - } - // Need to set it to the current time so Sync picks it up. - long modified = System.currentTimeMillis(); - byte[] data = cursor.getBlob(faviconCol); - mDB.updateBookmarkInBatch(mCr, mOperations, - url, title, null, -1, - created, modified, - BrowserContract.Bookmarks.DEFAULT_POSITION, - null, Bookmarks.TYPE_BOOKMARK); - if (data != null) { - storeBitmap(data, url); - } - cursor.moveToNext(); - } - } - } finally { - if (cursor != null) - cursor.close(); - } - - flushBatchOperations(); - } - - public void mergeHistory() { - ArrayList<ContentValues> visitsToSynthesize = new ArrayList<>(); - Cursor cursor = null; - try { - cursor = query (LegacyBrowserProvider.BOOKMARKS_URI, - SAMSUNG_HISTORY_URI, - LegacyBrowserProvider.BookmarkColumns.BOOKMARK + " = 0 AND " + - LegacyBrowserProvider.BookmarkColumns.VISITS + " > 0"); - - if (cursor != null) { - final int dateCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.DATE); - final int faviconCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.FAVICON); - final int titleCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.TITLE); - final int urlCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.URL); - final int visitsCol = cursor.getColumnIndexOrThrow(LegacyBrowserProvider.BookmarkColumns.VISITS); - - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - String url = cursor.getString(urlCol); - String title = cursor.getString(titleCol); - long date = cursor.getLong(dateCol); - int visits = cursor.getInt(visitsCol); - byte[] data = cursor.getBlob(faviconCol); - mDB.updateHistoryInBatch(mCr, mOperations, url, title, date, visits); - if (data != null) { - storeBitmap(data, url); - } - ContentValues visitData = new ContentValues(); - visitData.put(LocalBrowserDB.HISTORY_VISITS_DATE, date); - visitData.put(LocalBrowserDB.HISTORY_VISITS_URL, url); - visitData.put(LocalBrowserDB.HISTORY_VISITS_COUNT, visits); - visitsToSynthesize.add(visitData); - cursor.moveToNext(); - } - } - } finally { - if (cursor != null) - cursor.close(); - } - - flushBatchOperations(); - - // Now that we have flushed history records, we need to synthesize individual visits. We have - // gathered information about all of the visits we need to synthesize into visitsForSynthesis. - mDB.insertVisitsFromImportHistoryInBatch(mCr, mOperations, visitsToSynthesize); - - flushBatchOperations(); - } - - private void storeBitmap(byte[] data, String url) { - if (TextUtils.isEmpty(url) || data == null) { - return; - } - - final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - if (bitmap == null) { - return; - } - - final String iconUrl = IconsHelper.guessDefaultFaviconURL(url); - if (iconUrl == null) { - return; - } - - final DiskStorage storage = DiskStorage.get(mContext); - - storage.putIcon(url, bitmap); - storage.putMapping(url, iconUrl); - } - - protected Cursor query(Uri mainUri, Uri fallbackUri, String condition) { - final Cursor cursor = mCr.query(mainUri, null, condition, null, null); - if (Build.MANUFACTURER.equals(SAMSUNG_MANUFACTURER) && (cursor == null || cursor.getCount() == 0)) { - if (cursor != null) { - cursor.close(); - } - return mCr.query(fallbackUri, null, null, null, null); - } - return cursor; - } - - protected void flushBatchOperations() { - Log.d(LOGTAG, "Flushing " + mOperations.size() + " DB operations"); - try { - // We don't really care for the results, this is best-effort. - mCr.applyBatch(BrowserContract.AUTHORITY, mOperations); - } catch (RemoteException e) { - Log.e(LOGTAG, "Remote exception while updating db: ", e); - } catch (OperationApplicationException e) { - // Bug 716729 means this happens even in normal circumstances - Log.d(LOGTAG, "Error while applying database updates: ", e); - } - mOperations.clear(); - } - - @Override - public void run() { - if (mImportBookmarks) { - mergeBookmarks(); - } - if (mImportHistory) { - mergeHistory(); - } - - mOnDoneRunnable.run(); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImportPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImportPreference.java deleted file mode 100644 index 0f1d3ec3f..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/AndroidImportPreference.java +++ /dev/null @@ -1,112 +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.AppConstants.Versions; -import org.mozilla.gecko.R; -import org.mozilla.gecko.restrictions.Restrictable; -import org.mozilla.gecko.restrictions.Restrictions; -import org.mozilla.gecko.util.ThreadUtils; - -import java.util.Set; - -import android.app.ProgressDialog; -import android.content.Context; -import android.preference.Preference; -import android.util.AttributeSet; -import android.util.Log; - -class AndroidImportPreference extends MultiPrefMultiChoicePreference { - private static final String LOGTAG = "AndroidImport"; - public static final String PREF_KEY = "android.not_a_preference.import_android"; - private static final String PREF_KEY_PREFIX = "import_android.data."; - private final Context mContext; - - public static class Handler implements GeckoPreferences.PrefHandler { - public boolean setupPref(Context context, Preference pref) { - // Feature disabled on devices running Android M+ (Bug 1183559) - return Versions.preMarshmallow && Restrictions.isAllowed(context, Restrictable.IMPORT_SETTINGS); - } - - public void onChange(Context context, Preference pref, Object newValue) { } - } - - public AndroidImportPreference(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - - if (!positiveResult) - return; - - boolean bookmarksChecked = false; - boolean historyChecked = false; - - Set<String> values = getValues(); - - for (String value : values) { - // Import 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)) { - bookmarksChecked = true; - } else if ("history".equals(key)) { - historyChecked = true; - } - } - - runImport(bookmarksChecked, historyChecked); - } - - protected void runImport(final boolean doBookmarks, final boolean doHistory) { - Log.i(LOGTAG, "Importing Android history/bookmarks"); - if (!doBookmarks && !doHistory) { - return; - } - - final String dialogTitle; - if (doBookmarks && doHistory) { - dialogTitle = mContext.getString(R.string.bookmarkhistory_import_both); - } else if (doBookmarks) { - dialogTitle = mContext.getString(R.string.bookmarkhistory_import_bookmarks); - } else { - dialogTitle = mContext.getString(R.string.bookmarkhistory_import_history); - } - - final ProgressDialog dialog = - ProgressDialog.show(mContext, - dialogTitle, - mContext.getString(R.string.bookmarkhistory_import_wait), - true); - - final Runnable stopCallback = new Runnable() { - @Override - public void run() { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - dialog.dismiss(); - } - }); - } - }; - - ThreadUtils.postToBackgroundThread( - // Constructing AndroidImport may need finding the profile, - // which hits disk, so it needs to go into a Runnable too. - new Runnable() { - @Override - public void run() { - new AndroidImport(mContext, stopCallback, doBookmarks, doHistory).run(); - } - } - ); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/AppCompatPreferenceActivity.java b/mobile/android/base/java/org/mozilla/gecko/preferences/AppCompatPreferenceActivity.java deleted file mode 100644 index fb4a8f751..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/AppCompatPreferenceActivity.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 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 org.mozilla.gecko.preferences; - - -import android.content.res.Configuration; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatDelegate; -import android.support.v7.widget.Toolbar; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; - -/** - * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls - * to be used with AppCompat. - * - * This technique can be used with an {@link android.app.Activity} class, not just - * {@link android.preference.PreferenceActivity}. - * - * This class was directly imported (without any modifications) from Android SDK examples, at: - * https://android.googlesource.com/platform/development/+/master/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java - */ -public abstract class AppCompatPreferenceActivity extends PreferenceActivity { - private AppCompatDelegate mDelegate; - @Override - protected void onCreate(Bundle savedInstanceState) { - getDelegate().installViewFactory(); - getDelegate().onCreate(savedInstanceState); - super.onCreate(savedInstanceState); - } - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - getDelegate().onPostCreate(savedInstanceState); - } - public ActionBar getSupportActionBar() { - return getDelegate().getSupportActionBar(); - } - public void setSupportActionBar(@Nullable Toolbar toolbar) { - getDelegate().setSupportActionBar(toolbar); - } - @Override - public MenuInflater getMenuInflater() { - return getDelegate().getMenuInflater(); - } - @Override - public void setContentView(@LayoutRes int layoutResID) { - getDelegate().setContentView(layoutResID); - } - @Override - public void setContentView(View view) { - getDelegate().setContentView(view); - } - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().setContentView(view, params); - } - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().addContentView(view, params); - } - @Override - protected void onPostResume() { - super.onPostResume(); - getDelegate().onPostResume(); - } - @Override - protected void onTitleChanged(CharSequence title, int color) { - super.onTitleChanged(title, color); - getDelegate().setTitle(title); - } - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - getDelegate().onConfigurationChanged(newConfig); - } - @Override - protected void onStop() { - super.onStop(); - getDelegate().onStop(); - } - @Override - protected void onDestroy() { - super.onDestroy(); - getDelegate().onDestroy(); - } - public void invalidateOptionsMenu() { - getDelegate().invalidateOptionsMenu(); - } - private AppCompatDelegate getDelegate() { - if (mDelegate == null) { - mDelegate = AppCompatDelegate.create(this, null); - } - return mDelegate; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/ClearOnShutdownPref.java b/mobile/android/base/java/org/mozilla/gecko/preferences/ClearOnShutdownPref.java deleted file mode 100644 index 5218cd06d..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/ClearOnShutdownPref.java +++ /dev/null @@ -1,37 +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 boolean 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); - return true; - } - - @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); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomCheckBoxPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/CustomCheckBoxPreference.java deleted file mode 100644 index 2934ca88e..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomCheckBoxPreference.java +++ /dev/null @@ -1,44 +0,0 @@ -/* 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.preference.CheckBoxPreference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * Represents a Checkbox element in a preference menu. - * The title of the Checkbox can be larger than the view. - * In this case, it will be displayed in 2 or more lines. - * The default behavior of the class CheckBoxPreference - * doesn't wrap the title. - */ - -public class CustomCheckBoxPreference extends CheckBoxPreference { - - public CustomCheckBoxPreference(Context context) { - super(context); - } - - public CustomCheckBoxPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - public CustomCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - final TextView title = (TextView) view.findViewById(android.R.id.title); - if (title != null) { - title.setSingleLine(false); - title.setEllipsize(null); - } - } - -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListCategory.java b/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListCategory.java deleted file mode 100644 index ee5a46bef..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListCategory.java +++ /dev/null @@ -1,72 +0,0 @@ -/* 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.preference.PreferenceCategory; -import android.util.AttributeSet; - -public abstract class CustomListCategory extends PreferenceCategory { - protected CustomListPreference mDefaultReference; - - public CustomListCategory(Context context) { - super(context); - } - - public CustomListCategory(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public CustomListCategory(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onAttachedToActivity() { - super.onAttachedToActivity(); - - setOrderingAsAdded(true); - } - - /** - * Set the default to some available list item. Used if the current default is removed or - * disabled. - */ - protected void setFallbackDefault() { - if (getPreferenceCount() > 0) { - CustomListPreference aItem = (CustomListPreference) getPreference(0); - setDefault(aItem); - } - } - - /** - * Removes the given item from the set of available list items. - * This only updates the UI, so callers are responsible for persisting any state. - * - * @param item The given item to remove. - */ - public void uninstall(CustomListPreference item) { - removePreference(item); - if (item == mDefaultReference) { - // If the default is being deleted, set a new default. - setFallbackDefault(); - } - } - - /** - * Sets the given item as the current default. - * This only updates the UI, so callers are responsible for persisting any state. - * - * @param item The intended new default. - */ - public void setDefault(CustomListPreference item) { - if (mDefaultReference != null) { - mDefaultReference.setIsDefault(false); - } - - item.setIsDefault(true); - mDefaultReference = item; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListPreference.java deleted file mode 100644 index 8b7e0e7b3..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/CustomListPreference.java +++ /dev/null @@ -1,182 +0,0 @@ -/* 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 android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.preference.Preference; -import android.view.View; -import android.widget.TextView; - -/** - * Represents an element in a <code>CustomListCategory</code> preference menu. - * This preference con display a dialog when clicked, and also supports - * being set as a default item within the preference list category. - */ - -public abstract class CustomListPreference extends Preference implements View.OnLongClickListener { - protected String LOGTAG = "CustomListPreference"; - - // Indices of the buttons of the Dialog. - public static final int INDEX_SET_DEFAULT_BUTTON = 0; - - // Dialog item labels. - private String[] mDialogItems; - - // Dialog displayed when this element is tapped. - protected AlertDialog mDialog; - - // Cache label to avoid repeated use of the resource system. - protected final String LABEL_IS_DEFAULT; - protected final String LABEL_SET_AS_DEFAULT; - protected final String LABEL_REMOVE; - - protected boolean mIsDefault; - - // Enclosing parent category that contains this preference. - protected final CustomListCategory mParentCategory; - - /** - * Create a preference object to represent a list preference that is attached to - * a category. - * - * @param context The activity context we operate under. - * @param parentCategory The PreferenceCategory this object exists within. - */ - public CustomListPreference(Context context, CustomListCategory parentCategory) { - super(context); - - mParentCategory = parentCategory; - setLayoutResource(getPreferenceLayoutResource()); - - setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - CustomListPreference sPref = (CustomListPreference) preference; - sPref.showDialog(); - return true; - } - }); - - Resources res = getContext().getResources(); - - // Fetch these strings now, instead of every time we ever want to relabel a button. - LABEL_IS_DEFAULT = res.getString(R.string.pref_default); - LABEL_SET_AS_DEFAULT = res.getString(R.string.pref_dialog_set_default); - LABEL_REMOVE = res.getString(R.string.pref_dialog_remove); - } - - /** - * Returns the Android resource id for the layout. - */ - protected abstract int getPreferenceLayoutResource(); - - /** - * Set whether this object's UI should display this as the default item. - * Note: This must be called from the UI thread because it touches the view hierarchy. - * - * To ensure proper ordering, this method should only be called after this Preference - * is added to the PreferenceCategory. - * - * @param isDefault Flag indicating if this represents the default list item. - */ - public void setIsDefault(boolean isDefault) { - mIsDefault = isDefault; - if (isDefault) { - setOrder(0); - setSummary(LABEL_IS_DEFAULT); - } else { - setOrder(1); - setSummary(""); - } - } - - private String[] getCachedDialogItems() { - if (mDialogItems == null) { - mDialogItems = createDialogItems(); - } - return mDialogItems; - } - - /** - * Returns the strings to be displayed in the dialog. - */ - abstract protected String[] createDialogItems(); - - /** - * Display a dialog for this preference, when the preference is clicked. - */ - public void showDialog() { - final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(getTitle().toString()); - builder.setItems(getCachedDialogItems(), new DialogInterface.OnClickListener() { - // Forward relevant events to the container class for handling. - @Override - public void onClick(DialogInterface dialog, int indexClicked) { - hideDialog(); - onDialogIndexClicked(indexClicked); - } - }); - - configureDialogBuilder(builder); - - // We have to construct the dialog itself on the UI thread. - mDialog = builder.create(); - mDialog.setOnShowListener(new DialogInterface.OnShowListener() { - // Called when the dialog is shown (so we're finally able to manipulate button enabledness). - @Override - public void onShow(DialogInterface dialog) { - configureShownDialog(); - } - }); - mDialog.show(); - } - - /** - * (Optional) Configure the AlertDialog builder. - */ - protected void configureDialogBuilder(AlertDialog.Builder builder) { - return; - } - - abstract protected void onDialogIndexClicked(int index); - - /** - * Disables buttons in the shown AlertDialog as required. The button elements are not created - * until after show is called, so this method has to be called from the onShowListener above. - * @see this.showDialog - */ - protected void configureShownDialog() { - // If this is already the default list item, disable the button for setting this as the default. - final TextView defaultButton = (TextView) mDialog.getListView().getChildAt(INDEX_SET_DEFAULT_BUTTON); - if (mIsDefault) { - defaultButton.setEnabled(false); - - // Failure to unregister this listener leads to tapping the button dismissing the dialog - // without doing anything. - defaultButton.setOnClickListener(null); - } - } - - /** - * Hide the dialog we previously created, if any. - */ - public void hideDialog() { - if (mDialog != null && mDialog.isShowing()) { - mDialog.dismiss(); - } - } - - @Override - public boolean onLongClick(View view) { - // Show the preference dialog on long-press. - showDialog(); - return true; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/DistroSharedPrefsImport.java b/mobile/android/base/java/org/mozilla/gecko/preferences/DistroSharedPrefsImport.java deleted file mode 100644 index 1e235640e..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/DistroSharedPrefsImport.java +++ /dev/null @@ -1,61 +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.preferences; - -import org.mozilla.gecko.GeckoSharedPrefs; -import org.mozilla.gecko.distribution.Distribution; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Iterator; - -public class DistroSharedPrefsImport { - - public static final String LOGTAG = DistroSharedPrefsImport.class.getSimpleName(); - - public static void importPreferences(final Context context, final Distribution distribution) { - if (distribution == null) { - return; - } - - final JSONObject preferences = distribution.getAndroidPreferences(); - if (preferences.length() == 0) { - return; - } - - final Iterator<?> keys = preferences.keys(); - final SharedPreferences.Editor sharedPreferences = GeckoSharedPrefs.forProfile(context).edit(); - - while (keys.hasNext()) { - final String key = (String) keys.next(); - final Object value; - try { - value = preferences.get(key); - } catch (JSONException e) { - Log.e(LOGTAG, "Unable to completely process Android Preferences JSON.", e); - continue; - } - - // We currently don't support Float preferences. - if (value instanceof String) { - sharedPreferences.putString(GeckoPreferences.NON_PREF_PREFIX + key, (String) value); - } else if (value instanceof Boolean) { - sharedPreferences.putBoolean(GeckoPreferences.NON_PREF_PREFIX + key, (boolean) value); - } else if (value instanceof Integer) { - sharedPreferences.putInt(GeckoPreferences.NON_PREF_PREFIX + key, (int) value); - } else if (value instanceof Long) { - sharedPreferences.putLong(GeckoPreferences.NON_PREF_PREFIX + key, (long) value); - } else { - Log.d(LOGTAG, "Unknown preference value type whilst importing android preferences from distro file."); - } - } - sharedPreferences.apply(); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/FontSizePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/FontSizePreference.java deleted file mode 100644 index c77c2cc23..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/FontSizePreference.java +++ /dev/null @@ -1,192 +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 android.app.AlertDialog; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Color; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ScrollView; -import android.widget.TextView; - -import java.util.HashMap; - -class FontSizePreference extends DialogPreference { - private static final String LOGTAG = "FontSizePreference"; - private static final int TWIP_TO_PT_RATIO = 20; // 20 twip = 1 point. - private static final int PREVIEW_FONT_SIZE_UNIT = TypedValue.COMPLEX_UNIT_PT; - private static final int DEFAULT_FONT_INDEX = 2; - - private final Context mContext; - /** Container for mPreviewFontView to allow for scrollable padding at the top of the view. */ - private ScrollView mScrollingContainer; - private TextView mPreviewFontView; - private Button mIncreaseFontButton; - private Button mDecreaseFontButton; - - private final String[] mFontTwipValues; - private final String[] mFontSizeNames; // Ex: "Small". - /** Index into the above arrays for the saved preference value (from Gecko). */ - private int mSavedFontIndex = DEFAULT_FONT_INDEX; - /** Index into the above arrays for the currently displayed font size (the preview). */ - private int mPreviewFontIndex = mSavedFontIndex; - private final HashMap<String, Integer> mFontTwipToIndexMap; - - public FontSizePreference(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - - final Resources res = mContext.getResources(); - mFontTwipValues = res.getStringArray(R.array.pref_font_size_values); - mFontSizeNames = res.getStringArray(R.array.pref_font_size_entries); - mFontTwipToIndexMap = new HashMap<String, Integer>(); - for (int i = 0; i < mFontTwipValues.length; ++i) { - mFontTwipToIndexMap.put(mFontTwipValues[i], i); - } - } - - @Override - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { - final LayoutInflater inflater = - (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View dialogView = inflater.inflate(R.layout.font_size_preference, null); - initInternalViews(dialogView); - updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]); - - builder.setTitle(null); - builder.setView(dialogView); - } - - /** Saves relevant views to instance variables and initializes their settings. */ - private void initInternalViews(View dialogView) { - mScrollingContainer = (ScrollView) dialogView.findViewById(R.id.scrolling_container); - // Background cannot be set in XML (see bug 783597 - TODO: Change this to XML when bug is fixed). - mScrollingContainer.setBackgroundColor(Color.WHITE); - mPreviewFontView = (TextView) dialogView.findViewById(R.id.preview); - - mDecreaseFontButton = (Button) dialogView.findViewById(R.id.decrease_preview_font_button); - mIncreaseFontButton = (Button) dialogView.findViewById(R.id.increase_preview_font_button); - setButtonState(mPreviewFontIndex); - mDecreaseFontButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mPreviewFontIndex = Math.max(mPreviewFontIndex - 1, 0); - updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]); - mIncreaseFontButton.setEnabled(true); - // If we reached the minimum index, disable the button. - if (mPreviewFontIndex == 0) { - mDecreaseFontButton.setEnabled(false); - } - } - }); - mIncreaseFontButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mPreviewFontIndex = Math.min(mPreviewFontIndex + 1, mFontTwipValues.length - 1); - updatePreviewFontSize(mFontTwipValues[mPreviewFontIndex]); - - mDecreaseFontButton.setEnabled(true); - // If we reached the maximum index, disable the button. - if (mPreviewFontIndex == mFontTwipValues.length - 1) { - mIncreaseFontButton.setEnabled(false); - } - } - }); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - if (!positiveResult) { - mPreviewFontIndex = mSavedFontIndex; - return; - } - mSavedFontIndex = mPreviewFontIndex; - final String twipVal = mFontTwipValues[mSavedFontIndex]; - final OnPreferenceChangeListener prefChangeListener = getOnPreferenceChangeListener(); - if (prefChangeListener == null) { - Log.e(LOGTAG, "PreferenceChangeListener is null. FontSizePreference will not be saved to Gecko."); - return; - } - prefChangeListener.onPreferenceChange(this, twipVal); - } - - /** - * Finds the index of the given twip value and sets it as the saved preference value. Also the - * current preview text size to the given value. Does not update the mPreviewFontView text size. - */ - protected void setSavedFontSize(String twip) { - final Integer index = mFontTwipToIndexMap.get(twip); - if (index != null) { - mSavedFontIndex = index; - mPreviewFontIndex = mSavedFontIndex; - return; - } - resetSavedFontSizeToDefault(); - Log.e(LOGTAG, "setSavedFontSize: Given font size does not exist in twip values map. Reverted to default font size."); - } - - /** - * Updates the mPreviewFontView to the given text size, resets the container's scroll to the top - * left, and invalidates the view. Does not update the font indices. - */ - private void updatePreviewFontSize(String twip) { - float pt = convertTwipStrToPT(twip); - // Android will not render a font size of 0 pt but for Gecko, 0 twip turns off font - // inflation. Thus we special case 0 twip to display a renderable font size. - if (pt == 0) { - // Android adds an inexplicable extra margin on the smallest font size so to get around - // this, we reinflate the view. - ViewGroup parentView = (ViewGroup) mScrollingContainer.getParent(); - parentView.removeAllViews(); - final LayoutInflater inflater = - (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View dialogView = inflater.inflate(R.layout.font_size_preference, parentView); - initInternalViews(dialogView); - mPreviewFontView.setTextSize(PREVIEW_FONT_SIZE_UNIT, 1); - } else { - mPreviewFontView.setTextSize(PREVIEW_FONT_SIZE_UNIT, pt); - } - mScrollingContainer.scrollTo(0, 0); - } - - /** - * Resets the font indices to the default value. Does not update the mPreviewFontView text size. - */ - private void resetSavedFontSizeToDefault() { - mSavedFontIndex = DEFAULT_FONT_INDEX; - mPreviewFontIndex = mSavedFontIndex; - } - - private void setButtonState(int index) { - if (index == 0) { - mDecreaseFontButton.setEnabled(false); - } else if (index == mFontTwipValues.length - 1) { - mIncreaseFontButton.setEnabled(false); - } - } - - /** - * Returns the name of the font size (ex: "Small") at the currently saved preference value. - */ - protected String getSavedFontSizeName() { - return mFontSizeNames[mSavedFontIndex]; - } - - private float convertTwipStrToPT(String twip) { - return Float.parseFloat(twip) / TWIP_TO_PT_RATIO; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java deleted file mode 100644 index 6be9e6ea5..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java +++ /dev/null @@ -1,296 +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.Locale; - -import org.mozilla.gecko.AppConstants.Versions; -import org.mozilla.gecko.BrowserLocaleManager; -import org.mozilla.gecko.GeckoApplication; -import org.mozilla.gecko.GeckoSharedPrefs; -import org.mozilla.gecko.LocaleManager; -import org.mozilla.gecko.PrefsHelper; -import org.mozilla.gecko.R; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.TelemetryContract.Method; -import org.mozilla.gecko.fxa.AccountLoader; -import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; - -import android.accounts.Account; -import android.app.ActionBar; -import android.app.Activity; -import android.app.LoaderManager; -import android.content.Context; -import android.content.Loader; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; - -import com.squareup.leakcanary.RefWatcher; - -/* A simple implementation of PreferenceFragment for large screen devices - * This will strip category headers (so that they aren't shown to the user twice) - * as well as initializing Gecko prefs when a fragment is shown. -*/ -public class GeckoPreferenceFragment extends PreferenceFragment { - - public static final int ACCOUNT_LOADER_ID = 1; - private AccountLoaderCallbacks accountLoaderCallbacks; - private SyncPreference syncPreference; - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale); - - final Activity context = getActivity(); - - final LocaleManager localeManager = BrowserLocaleManager.getInstance(); - final Locale changed = localeManager.onSystemConfigurationChanged(context, getResources(), newConfig, lastLocale); - if (changed != null) { - applyLocale(changed); - } - } - - private static final String LOGTAG = "GeckoPreferenceFragment"; - private PrefsHelper.PrefHandler mPrefsRequest; - private Locale lastLocale = Locale.getDefault(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Write prefs to our custom GeckoSharedPrefs file. - getPreferenceManager().setSharedPreferencesName(GeckoSharedPrefs.APP_PREFS_NAME); - - int res = getResource(); - if (res == R.xml.preferences) { - Telemetry.startUISession(TelemetryContract.Session.SETTINGS); - } else { - final String resourceName = getArguments().getString("resource"); - Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, resourceName); - } - - // Display a menu for Search preferences. - if (res == R.xml.preferences_search) { - setHasOptionsMenu(true); - } - - addPreferencesFromResource(res); - - PreferenceScreen screen = getPreferenceScreen(); - setPreferenceScreen(screen); - mPrefsRequest = ((GeckoPreferences)getActivity()).setupPreferences(screen); - syncPreference = (SyncPreference) findPreference(GeckoPreferences.PREFS_SYNC); - } - - /** - * Return the title to use for this preference fragment. - * - * We only return titles for the preference screens that are - * launched directly, and thus might need to be redisplayed. - * - * This method sets the title that you see on non-multi-pane devices. - */ - private String getTitle() { - final int res = getResource(); - if (res == R.xml.preferences) { - return getString(R.string.settings_title); - } - - // We can launch this category from the Data Reporting notification. - if (res == R.xml.preferences_privacy) { - return getString(R.string.pref_category_privacy_short); - } - - // We can launch this category from the the magnifying glass in the quick search bar. - if (res == R.xml.preferences_search) { - return getString(R.string.pref_category_search); - } - - // Launched as action from content notifications. - if (res == R.xml.preferences_notifications) { - return getString(R.string.pref_category_notifications); - } - - return null; - } - - /** - * Return the header id for this preference fragment. This allows - * us to select the correct header when launching a preference - * screen directly. - * - * We only return titles for the preference screens that are - * launched directly. - */ - private int getHeader() { - final int res = getResource(); - if (res == R.xml.preferences) { - return R.id.pref_header_general; - } - - // We can launch this category from the Data Reporting notification. - if (res == R.xml.preferences_privacy) { - return R.id.pref_header_privacy; - } - - // We can launch this category from the the magnifying glass in the quick search bar. - if (res == R.xml.preferences_search) { - return R.id.pref_header_search; - } - - // Launched as action from content notifications. - if (res == R.xml.preferences_notifications) { - return R.id.pref_header_notifications; - } - - return -1; - } - - private void updateTitle() { - final String newTitle = getTitle(); - if (newTitle == null) { - Log.d(LOGTAG, "No new title to show."); - return; - } - - final GeckoPreferences activity = (GeckoPreferences) getActivity(); - if (activity.isMultiPane()) { - // In a multi-pane activity, the title is "Settings", and the action - // bar is along the top of the screen. We don't want to change those. - activity.showBreadCrumbs(newTitle, newTitle); - activity.switchToHeader(getHeader()); - return; - } - - Log.v(LOGTAG, "Setting activity title to " + newTitle); - activity.setTitle(newTitle); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - accountLoaderCallbacks = new AccountLoaderCallbacks(); - getLoaderManager().initLoader(ACCOUNT_LOADER_ID, null, accountLoaderCallbacks); - } - - @Override - public void onResume() { - // This is a little delicate. Ensure that you do nothing prior to - // super.onResume that you wouldn't do in onCreate. - applyLocale(Locale.getDefault()); - super.onResume(); - - // Force reload as the account may have been deleted while the app was in background. - getLoaderManager().restartLoader(ACCOUNT_LOADER_ID, null, accountLoaderCallbacks); - } - - private void applyLocale(final Locale currentLocale) { - final Context context = getActivity().getApplicationContext(); - - BrowserLocaleManager.getInstance().updateConfiguration(context, currentLocale); - - if (!currentLocale.equals(lastLocale)) { - // Locales differ. Let's redisplay. - Log.d(LOGTAG, "Locale changed: " + currentLocale); - this.lastLocale = currentLocale; - - // Rebuild the list to reflect the current locale. - getPreferenceScreen().removeAll(); - addPreferencesFromResource(getResource()); - } - - // Fix the parent title regardless. - updateTitle(); - } - - /* - * Get the resource from Fragment arguments and return it. - * - * If no resource can be found, return the resource id of the default preference screen. - */ - private int getResource() { - int resid = 0; - - final String resourceName = getArguments().getString("resource"); - final Activity activity = getActivity(); - - if (resourceName != null) { - // Fetch resource id by resource name. - final Resources resources = activity.getResources(); - final String packageName = activity.getPackageName(); - resid = resources.getIdentifier(resourceName, "xml", packageName); - } - - if (resid == 0) { - // The resource was invalid. Use the default resource. - Log.e(LOGTAG, "Failed to find resource: " + resourceName + ". Displaying default settings."); - - boolean isMultiPane = ((GeckoPreferences) activity).isMultiPane(); - resid = isMultiPane ? R.xml.preferences_general_tablet : R.xml.preferences; - } - - return resid; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.preferences_search_menu, menu); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (mPrefsRequest != null) { - PrefsHelper.removeObserver(mPrefsRequest); - mPrefsRequest = null; - } - - final int res = getResource(); - if (res == R.xml.preferences) { - Telemetry.stopUISession(TelemetryContract.Session.SETTINGS); - } - - GeckoApplication.watchReference(getActivity(), this); - } - - private class AccountLoaderCallbacks implements LoaderManager.LoaderCallbacks<Account> { - @Override - public Loader<Account> onCreateLoader(int id, Bundle args) { - return new AccountLoader(getActivity()); - } - - @Override - public void onLoadFinished(Loader<Account> loader, Account account) { - if (syncPreference == null) { - return; - } - - if (account == null) { - syncPreference.update(null); - return; - } - - syncPreference.update(new AndroidFxAccount(getActivity(), account)); - } - - @Override - public void onLoaderReset(Loader<Account> loader) { - if (syncPreference != null) { - syncPreference.update(null); - } - } - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java deleted file mode 100644 index aab5be2de..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java +++ /dev/null @@ -1,1514 +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.json.JSONArray; -import org.mozilla.gecko.AboutPages; -import org.mozilla.gecko.AdjustConstants; -import org.mozilla.gecko.AppConstants; -import org.mozilla.gecko.AppConstants.Versions; -import org.mozilla.gecko.BrowserApp; -import org.mozilla.gecko.BrowserLocaleManager; -import org.mozilla.gecko.DataReportingNotification; -import org.mozilla.gecko.DynamicToolbar; -import org.mozilla.gecko.EventDispatcher; -import org.mozilla.gecko.GeckoActivityStatus; -import org.mozilla.gecko.GeckoApp; -import org.mozilla.gecko.GeckoAppShell; -import org.mozilla.gecko.GeckoApplication; -import org.mozilla.gecko.GeckoProfile; -import org.mozilla.gecko.GeckoSharedPrefs; -import org.mozilla.gecko.LocaleManager; -import org.mozilla.gecko.Locales; -import org.mozilla.gecko.PrefsHelper; -import org.mozilla.gecko.R; -import org.mozilla.gecko.SnackbarBuilder; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.TelemetryContract.Method; -import org.mozilla.gecko.activitystream.ActivityStream; -import org.mozilla.gecko.background.common.GlobalConstants; -import org.mozilla.gecko.db.BrowserContract.SuggestedSites; -import org.mozilla.gecko.feeds.FeedService; -import org.mozilla.gecko.feeds.action.CheckForUpdatesAction; -import org.mozilla.gecko.permissions.Permissions; -import org.mozilla.gecko.restrictions.Restrictable; -import org.mozilla.gecko.restrictions.Restrictions; -import org.mozilla.gecko.tabqueue.TabQueueHelper; -import org.mozilla.gecko.tabqueue.TabQueuePrompt; -import org.mozilla.gecko.updater.UpdateService; -import org.mozilla.gecko.updater.UpdateServiceHelper; -import org.mozilla.gecko.util.ContextUtils; -import org.mozilla.gecko.util.EventCallback; -import org.mozilla.gecko.util.HardwareUtils; -import org.mozilla.gecko.util.InputOptionsUtils; -import org.mozilla.gecko.util.NativeEventListener; -import org.mozilla.gecko.util.NativeJSObject; -import org.mozilla.gecko.util.ThreadUtils; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.NotificationManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.content.res.Configuration; -import android.Manifest; -import android.os.Build; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; -import android.preference.PreferenceGroup; -import android.preference.SwitchPreference; -import android.preference.TwoStatePreference; -import android.support.design.widget.Snackbar; -import android.support.design.widget.TextInputLayout; -import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.ActionBar; -import android.text.Editable; -import android.text.InputType; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.ListView; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -public class GeckoPreferences -extends AppCompatPreferenceActivity -implements -GeckoActivityStatus, -NativeEventListener, -OnPreferenceChangeListener, -OnSharedPreferenceChangeListener -{ - private static final String LOGTAG = "GeckoPreferences"; - - // We have a white background, which makes transitions on - // some devices look bad. Don't use transitions on those - // devices. - private static final boolean NO_TRANSITIONS = HardwareUtils.IS_KINDLE_DEVICE; - private static final int NO_SUCH_ID = 0; - - public static final String NON_PREF_PREFIX = "android.not_a_preference."; - public static final String INTENT_EXTRA_RESOURCES = "resource"; - public static final String PREFS_TRACKING_PROTECTION_PROMPT_SHOWN = NON_PREF_PREFIX + "trackingProtectionPromptShown"; - public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled"; - public static final String PREFS_SYNC = NON_PREF_PREFIX + "sync"; - - private static boolean sIsCharEncodingEnabled; - private boolean mInitialized; - private PrefsHelper.PrefHandler mPrefsRequest; - private List<Header> mHeaders; - - // These match keys in resources/xml*/preferences*.xml - private static final String PREFS_SEARCH_RESTORE_DEFAULTS = NON_PREF_PREFIX + "search.restore_defaults"; - private static final String PREFS_DATA_REPORTING_PREFERENCES = NON_PREF_PREFIX + "datareporting.preferences"; - private static final String PREFS_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; - private static final String PREFS_CRASHREPORTER_ENABLED = "datareporting.crashreporter.submitEnabled"; - private static final String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding"; - private static final String PREFS_MP_ENABLED = "privacy.masterpassword.enabled"; - private static final String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload"; - private static final String PREFS_UPDATER_URL = "app.update.url.android"; - private static final String PREFS_GEO_REPORTING = NON_PREF_PREFIX + "app.geo.reportdata"; - private static final String PREFS_GEO_LEARN_MORE = NON_PREF_PREFIX + "geo.learn_more"; - private static final String PREFS_HEALTHREPORT_LINK = NON_PREF_PREFIX + "healthreport.link"; - private static final String PREFS_DEVTOOLS_REMOTE_USB_ENABLED = "devtools.remote.usb.enabled"; - private static final String PREFS_DEVTOOLS_REMOTE_WIFI_ENABLED = "devtools.remote.wifi.enabled"; - private static final String PREFS_DEVTOOLS_REMOTE_LINK = NON_PREF_PREFIX + "remote_debugging.link"; - private static final String PREFS_TRACKING_PROTECTION = "privacy.trackingprotection.state"; - private static final String PREFS_TRACKING_PROTECTION_PB = "privacy.trackingprotection.pbmode.enabled"; - private static final String PREFS_ZOOMED_VIEW_ENABLED = "ui.zoomedview.enabled"; - public static final String PREFS_VOICE_INPUT_ENABLED = NON_PREF_PREFIX + "voice_input_enabled"; - public static final String PREFS_QRCODE_ENABLED = NON_PREF_PREFIX + "qrcode_enabled"; - private static final String PREFS_TRACKING_PROTECTION_PRIVATE_BROWSING = "privacy.trackingprotection.pbmode.enabled"; - private static final String PREFS_TRACKING_PROTECTION_LEARN_MORE = NON_PREF_PREFIX + "trackingprotection.learn_more"; - private static final String PREFS_CLEAR_PRIVATE_DATA = NON_PREF_PREFIX + "privacy.clear"; - private static final String PREFS_CLEAR_PRIVATE_DATA_EXIT = NON_PREF_PREFIX + "history.clear_on_exit"; - private static final String PREFS_SCREEN_ADVANCED = NON_PREF_PREFIX + "advanced_screen"; - public static final String PREFS_HOMEPAGE = NON_PREF_PREFIX + "homepage"; - public static final String PREFS_HOMEPAGE_PARTNER_COPY = GeckoPreferences.PREFS_HOMEPAGE + ".partner"; - public static final String PREFS_HISTORY_SAVED_SEARCH = NON_PREF_PREFIX + "search.search_history.enabled"; - private static final String PREFS_FAQ_LINK = NON_PREF_PREFIX + "faq.link"; - private static final String PREFS_FEEDBACK_LINK = NON_PREF_PREFIX + "feedback.link"; - public static final String PREFS_NOTIFICATIONS_CONTENT = NON_PREF_PREFIX + "notifications.content"; - public static final String PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE = NON_PREF_PREFIX + "notifications.content.learn_more"; - public static final String PREFS_NOTIFICATIONS_WHATS_NEW = NON_PREF_PREFIX + "notifications.whats_new"; - public static final String PREFS_APP_UPDATE_LAST_BUILD_ID = "app.update.last_build_id"; - public static final String PREFS_READ_PARTNER_CUSTOMIZATIONS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_customizations_provider"; - public static final String PREFS_READ_PARTNER_BOOKMARKS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_bookmarks_provider"; - public static final String PREFS_CUSTOM_TABS = NON_PREF_PREFIX + "customtabs"; - public static final String PREFS_ACTIVITY_STREAM = NON_PREF_PREFIX + "activitystream"; - public static final String PREFS_CATEGORY_EXPERIMENTAL_FEATURES = NON_PREF_PREFIX + "category_experimental"; - - private static final String ACTION_STUMBLER_UPLOAD_PREF = "STUMBLER_PREF"; - - - // This isn't a Gecko pref, even if it looks like one. - private static final String PREFS_BROWSER_LOCALE = "locale"; - - public static final String PREFS_RESTORE_SESSION = NON_PREF_PREFIX + "restoreSession3"; - public static final String PREFS_RESTORE_SESSION_FROM_CRASH = "browser.sessionstore.resume_from_crash"; - public static final String PREFS_RESTORE_SESSION_MAX_CRASH_RESUMES = "browser.sessionstore.max_resumed_crashes"; - public static final String PREFS_TAB_QUEUE = NON_PREF_PREFIX + "tab_queue"; - public static final String PREFS_TAB_QUEUE_LAST_SITE = NON_PREF_PREFIX + "last_site"; - public static final String PREFS_TAB_QUEUE_LAST_TIME = NON_PREF_PREFIX + "last_time"; - - private static final String PREFS_DYNAMIC_TOOLBAR = "browser.chrome.dynamictoolbar"; - - // These values are chosen to be distinct from other Activity constants. - private static final int REQUEST_CODE_PREF_SCREEN = 5; - private static final int RESULT_CODE_EXIT_SETTINGS = 6; - - // Result code used when a locale preference changes. - // Callers can recognize this code to refresh themselves to - // accommodate a locale change. - public static final int RESULT_CODE_LOCALE_DID_CHANGE = 7; - - private static final int REQUEST_CODE_TAB_QUEUE = 8; - - private final Map<String, PrefHandler> HANDLERS; - { - final HashMap<String, PrefHandler> tempHandlers = new HashMap<>(2); - tempHandlers.put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref()); - tempHandlers.put(AndroidImportPreference.PREF_KEY, new AndroidImportPreference.Handler()); - HANDLERS = Collections.unmodifiableMap(tempHandlers); - } - - private SwitchPreference tabQueuePreference; - - /** - * Track the last locale so we know whether to redisplay. - */ - private Locale lastLocale = Locale.getDefault(); - private boolean localeSwitchingIsEnabled; - - private void startActivityForResultChoosingTransition(final Intent intent, final int requestCode) { - startActivityForResult(intent, requestCode); - if (NO_TRANSITIONS) { - overridePendingTransition(0, 0); - } - } - - private void finishChoosingTransition() { - finish(); - if (NO_TRANSITIONS) { - overridePendingTransition(0, 0); - } - } - private void updateActionBarTitle(int title) { - final String newTitle = getString(title); - if (newTitle != null) { - Log.v(LOGTAG, "Setting action bar title to " + newTitle); - - setTitle(newTitle); - } - } - - /** - * We only call this method for pre-HC versions of Android. - */ - private void updateTitleForPrefsResource(int res) { - // At present we only need to do this for non-leaf prefs views - // and the locale switcher itself. - int title = -1; - if (res == R.xml.preferences) { - title = R.string.settings_title; - } else if (res == R.xml.preferences_locale) { - title = R.string.pref_category_language; - } else if (res == R.xml.preferences_vendor) { - title = R.string.pref_category_vendor; - } else if (res == R.xml.preferences_general) { - title = R.string.pref_category_general; - } else if (res == R.xml.preferences_search) { - title = R.string.pref_category_search; - } - if (title != -1) { - setTitle(title); - } - } - - private void onLocaleChanged(Locale newLocale) { - Log.d(LOGTAG, "onLocaleChanged: " + newLocale); - - BrowserLocaleManager.getInstance().updateConfiguration(getApplicationContext(), newLocale); - this.lastLocale = newLocale; - - if (isMultiPane()) { - // This takes care of the left pane. - invalidateHeaders(); - - // Detach and reattach the current prefs pane so that it - // reflects the new locale. - final FragmentManager fragmentManager = getFragmentManager(); - int id = getResources().getIdentifier("android:id/prefs", null, null); - final Fragment current = fragmentManager.findFragmentById(id); - if (current != null) { - fragmentManager.beginTransaction() - .disallowAddToBackStack() - .detach(current) - .attach(current) - .commitAllowingStateLoss(); - } else { - Log.e(LOGTAG, "No prefs fragment to reattach!"); - } - - // Because Android just rebuilt the activity itself with the - // old language, we need to update the top title and other - // wording again. - if (onIsMultiPane()) { - updateActionBarTitle(R.string.settings_title); - } - - // Update the title to for the preference pane that we're currently showing. - final int titleId = getIntent().getExtras().getInt(PreferenceActivity.EXTRA_SHOW_FRAGMENT_TITLE); - if (titleId != NO_SUCH_ID) { - setTitle(titleId); - } else { - throw new IllegalStateException("Title id not found in intent bundle extras"); - } - - // Don't finish the activity -- we just reloaded all of the - // individual parts! -- but when it returns, make sure that the - // caller knows the locale changed. - setResult(RESULT_CODE_LOCALE_DID_CHANGE); - return; - } - - refreshSuggestedSites(); - - // Cause the current fragment to redisplay, the hard way. - // This avoids nonsense with trying to reach inside fragments and force them - // to redisplay themselves. - // We also don't need to update the title. - final Intent intent = (Intent) getIntent().clone(); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - startActivityForResultChoosingTransition(intent, REQUEST_CODE_PREF_SCREEN); - - setResult(RESULT_CODE_LOCALE_DID_CHANGE); - finishChoosingTransition(); - } - - private void checkLocale() { - final Locale currentLocale = Locale.getDefault(); - Log.v(LOGTAG, "Checking locale: " + currentLocale + " vs " + lastLocale); - if (currentLocale.equals(lastLocale)) { - return; - } - - onLocaleChanged(currentLocale); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - // Apply the current user-selected locale, if necessary. - checkLocale(); - - // Track this so we can decide whether to show locale options. - // See also the workaround below for Bug 1015209. - localeSwitchingIsEnabled = BrowserLocaleManager.getInstance().isEnabled(); - - // For Android v11+ where we use Fragments (v11+ only due to bug 866352), - // check that PreferenceActivity.EXTRA_SHOW_FRAGMENT has been set - // (or set it) before super.onCreate() is called so Android can display - // the correct Fragment resource. - // Note: this seems to only be required for non-multipane devices, multipane - // manages to automatically select the correct fragments. - if (!getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) { - // Set up the default fragment if there is no explicit fragment to show. - setupTopLevelFragmentIntent(); - } - - // We must call this before setTitle to avoid crashes. Most devices don't seem to care - // (we used to call onCreate later), however the ASUS TF300T (running 4.2) crashes - // with an NPE in android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(), and it's - // likely other strange devices (other Asus devices, some Samsungs) could do the same. - super.onCreate(savedInstanceState); - - if (onIsMultiPane()) { - // So that Android doesn't put the fragment title (or nothing at - // all) in the action bar. - updateActionBarTitle(R.string.settings_title); - - if (Build.VERSION.SDK_INT < 13) { - // Affected by Bug 1015209 -- no detach/attach. - // If we try rejigging fragments, we'll crash, so don't - // enable locale switching at all. - localeSwitchingIsEnabled = false; - throw new IllegalStateException("foobar"); - } - } - - // Use setResourceToOpen to specify these extras. - Bundle intentExtras = getIntent().getExtras(); - - EventDispatcher.getInstance().registerGeckoThreadListener(this, - "Sanitize:Finished", - "Snackbar:Show"); - - // Add handling for long-press click. - // This is only for Android 3.0 and below (which use the long-press-context-menu paradigm). - final ListView mListView = getListView(); - mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { - // Call long-click handler if it the item implements it. - final ListAdapter listAdapter = ((ListView) parent).getAdapter(); - final Object listItem = listAdapter.getItem(position); - - // Only CustomListPreference handles long clicks. - if (listItem instanceof CustomListPreference && listItem instanceof View.OnLongClickListener) { - final View.OnLongClickListener longClickListener = (View.OnLongClickListener) listItem; - return longClickListener.onLongClick(view); - } - return false; - } - }); - - // N.B., if we ever need to redisplay the locale selection UI without - // just finishing and recreating the activity, right here we'll need to - // capture EXTRA_SHOW_FRAGMENT_TITLE from the intent and store the title ID. - - // If launched from notification, explicitly cancel the notification. - if (intentExtras != null && intentExtras.containsKey(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION)) { - Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH, Method.NOTIFICATION, "settings-data-choices"); - NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode()); - } - - // Launched from "Notifications settings" action button in a notification. - if (intentExtras != null && intentExtras.containsKey(CheckForUpdatesAction.EXTRA_CONTENT_NOTIFICATION)) { - Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this)); - Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.BUTTON, "notification-settings"); - Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this)); - } - } - - /** - * Set intent to display top-level settings fragment, - * and show the correct title. - */ - private void setupTopLevelFragmentIntent() { - Intent intent = getIntent(); - // Check intent to determine settings screen to display. - Bundle intentExtras = intent.getExtras(); - Bundle fragmentArgs = new Bundle(); - // Add resource argument to fragment if it exists. - if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) { - String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES); - fragmentArgs.putString(INTENT_EXTRA_RESOURCES, resourceName); - } else { - // Use top-level settings screen. - if (!onIsMultiPane()) { - fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences"); - } else { - fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences_general_tablet"); - } - } - - // Build fragment intent. - intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName()); - intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs); - // Used to get fragment title when locale changes (see onLocaleChanged method above) - intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_TITLE, R.string.settings_title); - } - - @Override - public boolean isValidFragment(String fragmentName) { - return GeckoPreferenceFragment.class.getName().equals(fragmentName); - } - - @TargetApi(11) - @Override - public void onBuildHeaders(List<Header> target) { - if (onIsMultiPane()) { - loadHeadersFromResource(R.xml.preference_headers, target); - - Iterator<Header> iterator = target.iterator(); - - while (iterator.hasNext()) { - Header header = iterator.next(); - - if (header.id == R.id.pref_header_advanced && !Restrictions.isAllowed(this, Restrictable.ADVANCED_SETTINGS)) { - iterator.remove(); - } else if (header.id == R.id.pref_header_clear_private_data - && !Restrictions.isAllowed(this, Restrictable.CLEAR_HISTORY)) { - iterator.remove(); - } - } - - mHeaders = target; - } - } - - @TargetApi(11) - public void switchToHeader(int id) { - if (mHeaders == null) { - // Can't switch to a header if there are no headers! - return; - } - - for (Header header : mHeaders) { - if (header.id == id) { - switchToHeader(header); - return; - } - } - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - if (!hasFocus || mInitialized) - return; - - mInitialized = true; - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - - if (NO_TRANSITIONS) { - overridePendingTransition(0, 0); - } - - Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, Method.BACK, "settings"); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - EventDispatcher.getInstance().unregisterGeckoThreadListener(this, - "Sanitize:Finished", - "Snackbar:Show"); - - if (mPrefsRequest != null) { - PrefsHelper.removeObserver(mPrefsRequest); - mPrefsRequest = null; - } - } - - @Override - public void onPause() { - // Symmetric with onResume. - if (isMultiPane()) { - SharedPreferences prefs = GeckoSharedPrefs.forApp(this); - prefs.unregisterOnSharedPreferenceChangeListener(this); - } - - super.onPause(); - - if (getApplication() instanceof GeckoApplication) { - ((GeckoApplication) getApplication()).onActivityPause(this); - } - } - - @Override - public void onResume() { - super.onResume(); - - if (getApplication() instanceof GeckoApplication) { - ((GeckoApplication) getApplication()).onActivityResume(this); - } - - // Watch prefs, otherwise we don't reliably get told when they change. - // See documentation for onSharedPreferenceChange for more. - // Inexplicably only needed on tablet. - if (isMultiPane()) { - SharedPreferences prefs = GeckoSharedPrefs.forApp(this); - prefs.registerOnSharedPreferenceChangeListener(this); - } - } - - @Override - public void startActivity(Intent intent) { - // For settings, we want to be able to pass results up the chain - // of preference screens so Settings can behave as a single unit. - // Specifically, when we open a link, we want to back out of all - // the settings screens. - // We need to start nested PreferenceScreens withStartActivityForResult(). - // Android doesn't let us do that (see Preference.onClick), so we're overriding here. - startActivityForResultChoosingTransition(intent, REQUEST_CODE_PREF_SCREEN); - } - - @Override - public void startWithFragment(String fragmentName, Bundle args, - Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) { - Log.v(LOGTAG, "Starting with fragment: " + fragmentName + ", title " + titleRes); - - // Overriding because we want to use startActivityForResult for Fragment intents. - Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes); - if (resultTo == null) { - startActivityForResultChoosingTransition(intent, REQUEST_CODE_PREF_SCREEN); - } else { - resultTo.startActivityForResult(intent, resultRequestCode); - if (NO_TRANSITIONS) { - overridePendingTransition(0, 0); - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - // We might have just returned from a settings activity that allows us - // to switch locales, so reflect any change that occurred. - checkLocale(); - - switch (requestCode) { - case REQUEST_CODE_PREF_SCREEN: - switch (resultCode) { - case RESULT_CODE_EXIT_SETTINGS: - updateActionBarTitle(R.string.settings_title); - - // Pass this result up to the parent activity. - setResult(RESULT_CODE_EXIT_SETTINGS); - finishChoosingTransition(); - break; - } - break; - case REQUEST_CODE_TAB_QUEUE: - if (TabQueueHelper.processTabQueuePromptResponse(resultCode, this)) { - tabQueuePreference.setChecked(true); - } - break; - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - Permissions.onRequestPermissionsResult(this, permissions, grantResults); - } - - @Override - public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) { - try { - switch (event) { - case "Sanitize:Finished": - boolean success = message.getBoolean("success"); - final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail; - - SnackbarBuilder.builder(GeckoPreferences.this) - .message(stringRes) - .duration(Snackbar.LENGTH_LONG) - .buildAndShow(); - break; - case "Snackbar:Show": - SnackbarBuilder.builder(this) - .fromEvent(message) - .callback(callback) - .buildAndShow(); - break; - } - } catch (Exception e) { - Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); - } - } - - /** - * Initialize all of the preferences (native of Gecko ones) for this screen. - * - * @param prefs The android.preference.PreferenceGroup to initialize - * @return The integer id for the PrefsHelper.PrefHandlerBase listener added - * to monitor changes to Gecko prefs. - */ - public PrefsHelper.PrefHandler setupPreferences(PreferenceGroup prefs) { - ArrayList<String> list = new ArrayList<String>(); - setupPreferences(prefs, list); - return getGeckoPreferences(prefs, list); - } - - /** - * Recursively loop through a PreferenceGroup. Initialize native Android prefs, - * and build a list of Gecko preferences in the passed in prefs array - * - * @param preferences The android.preference.PreferenceGroup to initialize - * @param prefs An ArrayList to fill with Gecko preferences that need to be - * initialized - * @return The integer id for the PrefsHelper.PrefHandlerBase listener added - * to monitor changes to Gecko prefs. - */ - private void setupPreferences(PreferenceGroup preferences, ArrayList<String> prefs) { - for (int i = 0; i < preferences.getPreferenceCount(); i++) { - final Preference pref = preferences.getPreference(i); - - // Eliminate locale switching if necessary. - // This logic will need to be extended when - // content language selection (Bug 881510) is implemented. - if (!localeSwitchingIsEnabled && - "preferences_locale".equals(pref.getExtras().getString("resource"))) { - preferences.removePreference(pref); - i--; - continue; - } - - String key = pref.getKey(); - if (pref instanceof PreferenceGroup) { - // If datareporting is disabled, remove UI. - if (PREFS_DATA_REPORTING_PREFERENCES.equals(key)) { - if (!AppConstants.MOZ_DATA_REPORTING || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_SCREEN_ADVANCED.equals(key) && - !Restrictions.isAllowed(this, Restrictable.ADVANCED_SETTINGS)) { - preferences.removePreference(pref); - i--; - continue; - } else if (PREFS_CATEGORY_EXPERIMENTAL_FEATURES.equals(key) - && !AppConstants.MOZ_ANDROID_ACTIVITY_STREAM - && !AppConstants.MOZ_ANDROID_CUSTOM_TABS) { - preferences.removePreference(pref); - i--; - continue; - } - setupPreferences((PreferenceGroup) pref, prefs); - } else { - if (HANDLERS.containsKey(key)) { - PrefHandler handler = HANDLERS.get(key); - if (!handler.setupPref(this, pref)) { - preferences.removePreference(pref); - i--; - continue; - } - } - - pref.setOnPreferenceChangeListener(this); - if (PREFS_UPDATER_AUTODOWNLOAD.equals(key)) { - if (!AppConstants.MOZ_UPDATER || ContextUtils.isInstalledFromGooglePlay(this)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_TRACKING_PROTECTION.equals(key)) { - // Remove UI for global TP pref in non-Nightly builds. - if (!AppConstants.NIGHTLY_BUILD) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_TRACKING_PROTECTION_PB.equals(key)) { - // Remove UI for private-browsing-only TP pref in Nightly builds. - if (AppConstants.NIGHTLY_BUILD) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_TELEMETRY_ENABLED.equals(key)) { - if (!AppConstants.MOZ_TELEMETRY_REPORTING || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(key) || - PREFS_HEALTHREPORT_LINK.equals(key)) { - if (!AppConstants.MOZ_SERVICES_HEALTHREPORT || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_GEO_REPORTING.equals(key) || - PREFS_GEO_LEARN_MORE.equals(key)) { - if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_DEVTOOLS_REMOTE_USB_ENABLED.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.REMOTE_DEBUGGING)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_DEVTOOLS_REMOTE_WIFI_ENABLED.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.REMOTE_DEBUGGING)) { - preferences.removePreference(pref); - i--; - continue; - } - if (!InputOptionsUtils.supportsQrCodeReader(getApplicationContext())) { - // WiFi debugging requires a QR code reader - pref.setEnabled(false); - pref.setSummary(getString(R.string.pref_developer_remotedebugging_wifi_disabled_summary)); - continue; - } - } else if (PREFS_DEVTOOLS_REMOTE_LINK.equals(key)) { - // Remove the "Learn more" link if remote debugging is disabled - if (!Restrictions.isAllowed(this, Restrictable.REMOTE_DEBUGGING)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_RESTORE_SESSION.equals(key) || - PREFS_BROWSER_LOCALE.equals(key)) { - // Set the summary string to the current entry. The summary - // for other list prefs will be set in the PrefsHelper - // callback, but since this pref doesn't live in Gecko, we - // need to handle it separately. - ListPreference listPref = (ListPreference) pref; - CharSequence selectedEntry = listPref.getEntry(); - listPref.setSummary(selectedEntry); - continue; - } else if (PREFS_SYNC.equals(key)) { - // Don't show sync prefs while in guest mode. - if (!Restrictions.isAllowed(this, Restrictable.MODIFY_ACCOUNTS)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_SEARCH_RESTORE_DEFAULTS.equals(key)) { - pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - GeckoPreferences.this.restoreDefaultSearchEngines(); - Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH_RESTORE_DEFAULTS, Method.LIST_ITEM); - return true; - } - }); - } else if (PREFS_TAB_QUEUE.equals(key)) { - tabQueuePreference = (SwitchPreference) pref; - // Only show tab queue pref on nightly builds with the tab queue build flag. - if (!TabQueueHelper.TAB_QUEUE_ENABLED) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_ZOOMED_VIEW_ENABLED.equals(key)) { - if (!AppConstants.NIGHTLY_BUILD) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_VOICE_INPUT_ENABLED.equals(key)) { - if (!InputOptionsUtils.supportsVoiceRecognizer(getApplicationContext(), getResources().getString(R.string.voicesearch_prompt))) { - // Remove UI for voice input on non nightly builds. - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_QRCODE_ENABLED.equals(key)) { - if (!InputOptionsUtils.supportsQrCodeReader(getApplicationContext())) { - // Remove UI for qr code input on non nightly builds - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_TRACKING_PROTECTION_PRIVATE_BROWSING.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.PRIVATE_BROWSING)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_TRACKING_PROTECTION_LEARN_MORE.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.PRIVATE_BROWSING)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_MP_ENABLED.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.MASTER_PASSWORD)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_CLEAR_PRIVATE_DATA.equals(key) || PREFS_CLEAR_PRIVATE_DATA_EXIT.equals(key)) { - if (!Restrictions.isAllowed(this, Restrictable.CLEAR_HISTORY)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_HOMEPAGE.equals(key)) { - String setUrl = GeckoSharedPrefs.forProfile(getBaseContext()).getString(PREFS_HOMEPAGE, AboutPages.HOME); - setHomePageSummary(pref, setUrl); - pref.setOnPreferenceChangeListener(this); - } else if (PREFS_FAQ_LINK.equals(key)) { - // Format the FAQ link - final String VERSION = AppConstants.MOZ_APP_VERSION; - final String OS = AppConstants.OS_TARGET; - final String LOCALE = Locales.getLanguageTag(Locale.getDefault()); - - final String url = getResources().getString(R.string.faq_link, VERSION, OS, LOCALE); - ((LinkPreference) pref).setUrl(url); - } else if (PREFS_FEEDBACK_LINK.equals(key)) { - // Format the feedback link. We can't easily use this "app.feedbackURL" - // Gecko preference because the URL must be formatted. - final String url = getResources().getString(R.string.feedback_link, AppConstants.MOZ_APP_VERSION, AppConstants.MOZ_UPDATE_CHANNEL); - ((LinkPreference) pref).setUrl(url); - } else if (PREFS_DYNAMIC_TOOLBAR.equals(key)) { - if (DynamicToolbar.isForceDisabled()) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_NOTIFICATIONS_CONTENT.equals(key) || - PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE.equals(key)) { - if (!FeedService.isInExperiment(this)) { - preferences.removePreference(pref); - i--; - continue; - } - } else if (PREFS_CUSTOM_TABS.equals(key) && !AppConstants.MOZ_ANDROID_CUSTOM_TABS) { - preferences.removePreference(pref); - i--; - continue; - } else if (PREFS_ACTIVITY_STREAM.equals(key) && !ActivityStream.isUserEligible(this)) { - preferences.removePreference(pref); - i--; - continue; - } - - // Some Preference UI elements are not actually preferences, - // but they require a key to work correctly. For example, - // "Clear private data" requires a key for its state to be - // saved when the orientation changes. It uses the - // "android.not_a_preference.privacy.clear" key - which doesn't - // exist in Gecko - to satisfy this requirement. - if (isGeckoPref(key)) { - prefs.add(key); - } - } - } - } - - private void setHomePageSummary(Preference pref, String value) { - if (!TextUtils.isEmpty(value)) { - pref.setSummary(value); - } else { - pref.setSummary(AboutPages.HOME); - } - } - - private boolean isGeckoPref(String key) { - if (TextUtils.isEmpty(key)) { - return false; - } - - if (key.startsWith(NON_PREF_PREFIX)) { - return false; - } - - if (key.equals(PREFS_BROWSER_LOCALE)) { - return false; - } - - return true; - } - - /** - * Restore default search engines in Gecko and retrigger a search engine refresh. - */ - protected void restoreDefaultSearchEngines() { - GeckoAppShell.notifyObservers("SearchEngines:RestoreDefaults", null); - - // Send message to Gecko to get engines. SearchPreferenceCategory listens for the response. - GeckoAppShell.notifyObservers("SearchEngines:GetVisible", null); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int itemId = item.getItemId(); - switch (itemId) { - case android.R.id.home: - finishChoosingTransition(); - return true; - } - - // Generated R.id.* apparently aren't constant expressions, so they can't be switched. - if (itemId == R.id.restore_defaults) { - restoreDefaultSearchEngines(); - Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH_RESTORE_DEFAULTS, Method.MENU); - return true; - } - - return super.onOptionsItemSelected(item); - } - - final private int DIALOG_CREATE_MASTER_PASSWORD = 0; - final private int DIALOG_REMOVE_MASTER_PASSWORD = 1; - - public static void setCharEncodingState(boolean enabled) { - sIsCharEncodingEnabled = enabled; - } - - public static boolean getCharEncodingState() { - return sIsCharEncodingEnabled; - } - - public static void broadcastAction(final Context context, final Intent intent) { - fillIntentWithProfileInfo(context, intent); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); - } - - private static void fillIntentWithProfileInfo(final Context context, final Intent intent) { - // There is a race here, but GeckoProfile returns the default profile - // when Gecko is not explicitly running for a different profile. In a - // multi-profile world, this will need to be updated (possibly to - // broadcast settings for all profiles). See Bug 882182. - GeckoProfile profile = GeckoProfile.get(context); - if (profile != null) { - intent.putExtra("profileName", profile.getName()) - .putExtra("profilePath", profile.getDir().getAbsolutePath()); - } - } - - /** - * Broadcast the provided value as the value of the - * <code>PREFS_GEO_REPORTING</code> pref. - */ - public static void broadcastStumblerPref(final Context context, final boolean value) { - Intent intent = new Intent(ACTION_STUMBLER_UPLOAD_PREF) - .putExtra("pref", PREFS_GEO_REPORTING) - .putExtra("branch", GeckoSharedPrefs.APP_PREFS_NAME) - .putExtra("enabled", value) - .putExtra("moz_mozilla_api_key", AppConstants.MOZ_MOZILLA_API_KEY); - if (GeckoAppShell.getGeckoInterface() != null) { - intent.putExtra("user_agent", GeckoAppShell.getGeckoInterface().getDefaultUAString()); - } - broadcastAction(context, intent); - } - - /** - * Broadcast the current value of the - * <code>PREFS_GEO_REPORTING</code> pref. - */ - public static void broadcastStumblerPref(final Context context) { - final boolean value = getBooleanPref(context, PREFS_GEO_REPORTING, false); - broadcastStumblerPref(context, value); - } - - /** - * Return the value of the named preference in the default preferences file. - * - * This corresponds to the storage that backs preferences.xml. - * @param context a <code>Context</code>; the - * <code>PreferenceActivity</code> will suffice, but this - * method is intended to be called from other contexts - * within the application, not just this <code>Activity</code>. - * @param name the name of the preference to retrieve. - * @param def the default value to return if the preference is not present. - * @return the value of the preference, or the default. - */ - public static boolean getBooleanPref(final Context context, final String name, boolean def) { - final SharedPreferences prefs = GeckoSharedPrefs.forApp(context); - return prefs.getBoolean(name, def); - } - - /** - * Immediately handle the user's selection of a browser locale. - * - * Earlier locale-handling code did this with centralized logic in - * GeckoApp, delegating to LocaleManager for persistence and refreshing - * the activity as necessary. - * - * We no longer handle this by sending a message to GeckoApp, for - * several reasons: - * - * * GeckoApp might not be running. Activities don't always stick around. - * A Java bridge message might not be handled. - * * We need to adapt the preferences UI to the locale ourselves. - * * The user might not hit Back (or Up) -- they might hit Home and never - * come back. - * - * We handle the case of the user returning to the browser via the - * onActivityResult mechanism: see {@link BrowserApp#onActivityResult(int, int, Intent)}. - */ - private boolean onLocaleSelected(final String currentLocale, final String newValue) { - final Context context = getApplicationContext(); - - // LocaleManager operations need to occur on the background thread. - // ... but activity operations need to occur on the UI thread. So we - // have nested runnables. - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - final LocaleManager localeManager = BrowserLocaleManager.getInstance(); - - if (TextUtils.isEmpty(newValue)) { - BrowserLocaleManager.getInstance().resetToSystemLocale(context); - Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_RESET); - } else { - if (null == localeManager.setSelectedLocale(context, newValue)) { - localeManager.updateConfiguration(context, Locale.getDefault()); - } - Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_UNSELECTED, Method.NONE, - currentLocale == null ? "unknown" : currentLocale); - Telemetry.sendUIEvent(TelemetryContract.Event.LOCALE_BROWSER_SELECTED, Method.NONE, newValue); - } - - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - onLocaleChanged(Locale.getDefault()); - } - }); - } - }); - - return true; - } - - private void refreshSuggestedSites() { - final ContentResolver cr = getApplicationContext().getContentResolver(); - - // This will force all active suggested sites cursors - // to request a refresh (e.g. cursor loaders). - cr.notifyChange(SuggestedSites.CONTENT_URI, null); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale); - - if (lastLocale.equals(newConfig.locale)) { - Log.d(LOGTAG, "Old locale same as new locale. Short-circuiting."); - return; - } - - final LocaleManager localeManager = BrowserLocaleManager.getInstance(); - final Locale changed = localeManager.onSystemConfigurationChanged(this, getResources(), newConfig, lastLocale); - if (changed != null) { - onLocaleChanged(changed); - } - } - - /** - * Implementation for the {@link OnSharedPreferenceChangeListener} interface, - * which we use to watch changes in our prefs file. - * - * This is reliably called whenever the pref changes, which is not the case - * for multiple consecutive changes in the case of onPreferenceChange. - * - * Note that this listener is not always registered: we use it only on - * tablets, Honeycomb and up, where we'll have a multi-pane view and prefs - * changing multiple times. - */ - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (PREFS_BROWSER_LOCALE.equals(key)) { - onLocaleSelected(Locales.getLanguageTag(lastLocale), - sharedPreferences.getString(key, null)); - } - } - - public interface PrefHandler { - // Allows the pref to do any initialization it needs. Return false to have the pref removed - // from the prefs screen entirely. - public boolean setupPref(Context context, Preference pref); - public void onChange(Context context, Preference pref, Object newValue); - } - - private void recordSettingChangeTelemetry(String prefName, Object newValue) { - final String value; - if (newValue instanceof Boolean) { - value = (Boolean) newValue ? "1" : "0"; - } else if (prefName.equals(PREFS_HOMEPAGE)) { - // Don't record the user's homepage preference. - value = "*"; - } else { - value = newValue.toString(); - } - - final JSONArray extras = new JSONArray(); - extras.put(prefName); - extras.put(value); - Telemetry.sendUIEvent(TelemetryContract.Event.EDIT, Method.SETTINGS, extras.toString()); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String prefName = preference.getKey(); - Log.i(LOGTAG, "Changed " + prefName + " = " + newValue); - recordSettingChangeTelemetry(prefName, newValue); - - if (PREFS_MP_ENABLED.equals(prefName)) { - showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD); - - // We don't want the "use master password" pref to change until the - // user has gone through the dialog. - return false; - } - - if (PREFS_HOMEPAGE.equals(prefName)) { - setHomePageSummary(preference, String.valueOf(newValue)); - } - - if (PREFS_BROWSER_LOCALE.equals(prefName)) { - // Even though this is a list preference, we don't want to handle it - // below, so we return here. - return onLocaleSelected(Locales.getLanguageTag(lastLocale), (String) newValue); - } - - if (PREFS_MENU_CHAR_ENCODING.equals(prefName)) { - setCharEncodingState(((String) newValue).equals("true")); - } else if (PREFS_UPDATER_AUTODOWNLOAD.equals(prefName)) { - UpdateServiceHelper.setAutoDownloadPolicy(this, UpdateService.AutoDownloadPolicy.get((String) newValue)); - } else if (PREFS_UPDATER_URL.equals(prefName)) { - UpdateServiceHelper.setUpdateUrl(this, (String) newValue); - } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(prefName)) { - final Boolean newBooleanValue = (Boolean) newValue; - AdjustConstants.getAdjustHelper().setEnabled(newBooleanValue); - } else if (PREFS_GEO_REPORTING.equals(prefName)) { - if ((Boolean) newValue) { - enableStumbler((CheckBoxPreference) preference); - return false; - } else { - broadcastStumblerPref(GeckoPreferences.this, false); - return true; - } - } else if (PREFS_TAB_QUEUE.equals(prefName)) { - if ((Boolean) newValue && !TabQueueHelper.canDrawOverlays(this)) { - Intent promptIntent = new Intent(this, TabQueuePrompt.class); - startActivityForResult(promptIntent, REQUEST_CODE_TAB_QUEUE); - return false; - } - } else if (PREFS_NOTIFICATIONS_CONTENT.equals(prefName)) { - FeedService.setup(this); - } else if (PREFS_ACTIVITY_STREAM.equals(prefName)) { - ThreadUtils.postDelayedToUiThread(new Runnable() { - @Override - public void run() { - GeckoAppShell.scheduleRestart(); - } - }, 1000); - } else if (HANDLERS.containsKey(prefName)) { - PrefHandler handler = HANDLERS.get(prefName); - handler.onChange(this, preference, newValue); - } - - // Send Gecko-side pref changes to Gecko - if (isGeckoPref(prefName)) { - PrefsHelper.setPref(prefName, newValue, true /* flush */); - } - - if (preference instanceof ListPreference) { - // We need to find the entry for the new value - int newIndex = ((ListPreference) preference).findIndexOfValue((String) newValue); - CharSequence newEntry = ((ListPreference) preference).getEntries()[newIndex]; - ((ListPreference) preference).setSummary(newEntry); - } else if (preference instanceof LinkPreference) { - setResult(RESULT_CODE_EXIT_SETTINGS); - finishChoosingTransition(); - } else if (preference instanceof FontSizePreference) { - final FontSizePreference fontSizePref = (FontSizePreference) preference; - fontSizePref.setSummary(fontSizePref.getSavedFontSizeName()); - } - - return true; - } - - private void enableStumbler(final CheckBoxPreference preference) { - Permissions - .from(this) - .withPermissions(Manifest.permission.ACCESS_FINE_LOCATION) - .onUIThread() - .andFallback(new Runnable() { - @Override - public void run() { - preference.setChecked(false); - } - }) - .run(new Runnable() { - @Override - public void run() { - preference.setChecked(true); - broadcastStumblerPref(GeckoPreferences.this, true); - } - }); - } - - private TextInputLayout getTextBox(int aHintText) { - final EditText input = new EditText(this); - int inputtype = InputType.TYPE_CLASS_TEXT; - inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; - input.setInputType(inputtype); - - input.setHint(aHintText); - - final TextInputLayout layout = new TextInputLayout(this); - layout.addView(input); - - return layout; - } - - private class PasswordTextWatcher implements TextWatcher { - EditText input1; - EditText input2; - AlertDialog dialog; - - PasswordTextWatcher(EditText aInput1, EditText aInput2, AlertDialog aDialog) { - input1 = aInput1; - input2 = aInput2; - dialog = aDialog; - } - - @Override - public void afterTextChanged(Editable s) { - if (dialog == null) - return; - - String text1 = input1.getText().toString(); - String text2 = input2.getText().toString(); - boolean disabled = TextUtils.isEmpty(text1) || TextUtils.isEmpty(text2) || !text1.equals(text2); - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { } - } - - private class EmptyTextWatcher implements TextWatcher { - EditText input; - AlertDialog dialog; - - EmptyTextWatcher(EditText aInput, AlertDialog aDialog) { - input = aInput; - dialog = aDialog; - } - - @Override - public void afterTextChanged(Editable s) { - if (dialog == null) - return; - - String text = input.getText().toString(); - boolean disabled = TextUtils.isEmpty(text); - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { } - } - - @Override - protected Dialog onCreateDialog(int id) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - LinearLayout linearLayout = new LinearLayout(this); - linearLayout.setOrientation(LinearLayout.VERTICAL); - AlertDialog dialog; - switch (id) { - case DIALOG_CREATE_MASTER_PASSWORD: - final TextInputLayout inputLayout1 = getTextBox(R.string.masterpassword_password); - final TextInputLayout inputLayout2 = getTextBox(R.string.masterpassword_confirm); - linearLayout.addView(inputLayout1); - linearLayout.addView(inputLayout2); - - final EditText input1 = inputLayout1.getEditText(); - final EditText input2 = inputLayout2.getEditText(); - - builder.setTitle(R.string.masterpassword_create_title) - .setView((View) linearLayout) - .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - PrefsHelper.setPref(PREFS_MP_ENABLED, - input1.getText().toString(), - /* flush */ true); - } - }) - .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - return; - } - }); - dialog = builder.create(); - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - input1.setText(""); - input2.setText(""); - input1.requestFocus(); - } - }); - - PasswordTextWatcher watcher = new PasswordTextWatcher(input1, input2, dialog); - input1.addTextChangedListener((TextWatcher) watcher); - input2.addTextChangedListener((TextWatcher) watcher); - - break; - case DIALOG_REMOVE_MASTER_PASSWORD: - final TextInputLayout inputLayout = getTextBox(R.string.masterpassword_password); - linearLayout.addView(inputLayout); - final EditText input = inputLayout.getEditText(); - - builder.setTitle(R.string.masterpassword_remove_title) - .setView((View) linearLayout) - .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - PrefsHelper.setPref(PREFS_MP_ENABLED, input.getText().toString()); - } - }) - .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - return; - } - }); - dialog = builder.create(); - dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - input.setText(""); - } - }); - dialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - input.setText(""); - } - }); - input.addTextChangedListener(new EmptyTextWatcher(input, dialog)); - break; - default: - return null; - } - - return dialog; - } - - // Initialize preferences by requesting the preference values from Gecko - private static class PrefCallbacks extends PrefsHelper.PrefHandlerBase { - private final PreferenceGroup screen; - - public PrefCallbacks(final PreferenceGroup screen) { - this.screen = screen; - } - - private Preference getField(String prefName) { - return screen.findPreference(prefName); - } - - @Override - public void prefValue(String prefName, final boolean value) { - final TwoStatePreference pref = (TwoStatePreference) getField(prefName); - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - if (pref.isChecked() != value) { - pref.setChecked(value); - } - } - }); - } - - @Override - public void prefValue(String prefName, final String value) { - final Preference pref = getField(prefName); - if (pref instanceof EditTextPreference) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - ((EditTextPreference) pref).setText(value); - } - }); - } else if (pref instanceof ListPreference) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - ((ListPreference) pref).setValue(value); - // Set the summary string to the current entry - CharSequence selectedEntry = ((ListPreference) pref).getEntry(); - ((ListPreference) pref).setSummary(selectedEntry); - } - }); - } else if (pref instanceof FontSizePreference) { - final FontSizePreference fontSizePref = (FontSizePreference) pref; - fontSizePref.setSavedFontSize(value); - final String fontSizeName = fontSizePref.getSavedFontSizeName(); - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - fontSizePref.setSummary(fontSizeName); // Ex: "Small". - } - }); - } - } - - @Override - public void prefValue(String prefName, final int value) { - final Preference pref = getField(prefName); - Log.w(LOGTAG, "Unhandled int value for pref [" + pref + "]"); - } - - @Override - public void finish() { - // enable all preferences once we have them from gecko - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - screen.setEnabled(true); - } - }); - } - } - - private PrefsHelper.PrefHandler getGeckoPreferences(final PreferenceGroup screen, - ArrayList<String> prefs) { - final PrefsHelper.PrefHandler prefHandler = new PrefCallbacks(screen); - final String[] prefNames = prefs.toArray(new String[prefs.size()]); - PrefsHelper.addObserver(prefNames, prefHandler); - return prefHandler; - } - - @Override - public boolean isGeckoActivityOpened() { - return false; - } - - /** - * Given an Intent instance, add extras to specify which settings section to - * open. - * - * resource should be a valid Android XML resource identifier. - * - * The mechanism to open a section differs based on Android version. - */ - public static void setResourceToOpen(final Intent intent, final String resource) { - if (intent == null) { - throw new IllegalArgumentException("intent must not be null"); - } - if (resource == null) { - return; - } - - intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName()); - - Bundle fragmentArgs = new Bundle(); - fragmentArgs.putString("resource", resource); - intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/LinkPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/LinkPreference.java deleted file mode 100644 index 774f78c53..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/LinkPreference.java +++ /dev/null @@ -1,35 +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.Tabs; - -import android.content.Context; -import android.preference.Preference; -import android.util.AttributeSet; - -class LinkPreference extends Preference { - private String mUrl; - - public LinkPreference(Context context, AttributeSet attrs) { - super(context, attrs); - mUrl = attrs.getAttributeValue(null, "url"); - } - public LinkPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mUrl = attrs.getAttributeValue(null, "url"); - } - - public void setUrl(String url) { - mUrl = url; - } - - @Override - protected void onClick() { - Tabs.getInstance().loadUrlInTab(mUrl); - callChangeListener(mUrl); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/ListCheckboxPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/ListCheckboxPreference.java deleted file mode 100644 index f56ea58b9..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/ListCheckboxPreference.java +++ /dev/null @@ -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 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; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/LocaleListPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/LocaleListPreference.java deleted file mode 100644 index c962a3d19..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/LocaleListPreference.java +++ /dev/null @@ -1,316 +0,0 @@ -/* 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.nio.ByteBuffer; -import java.text.Collator; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; - -import org.mozilla.gecko.AppConstants.Versions; -import org.mozilla.gecko.BrowserLocaleManager; -import org.mozilla.gecko.Locales; -import org.mozilla.gecko.R; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.preference.ListPreference; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; - -public class LocaleListPreference extends ListPreference { - private static final String LOG_TAG = "GeckoLocaleList"; - - /** - * With thanks to <http://stackoverflow.com/a/22679283/22003> for the - * initial solution. - * - * This class encapsulates an approach to checking whether a script - * is usable on a device. We attempt to draw a character from the - * script (e.g., ব). If the fonts on the device don't have the correct - * glyph, Android typically renders whitespace (rather than .notdef). - * - * Pass in part of the name of the locale in its local representation, - * and a whitespace character; this class performs the graphical comparison. - * - * See Bug 1023451 Comment 24 for extensive explanation. - */ - private static class CharacterValidator { - private static final int BITMAP_WIDTH = 32; - private static final int BITMAP_HEIGHT = 48; - - private final Paint paint = new Paint(); - private final byte[] missingCharacter; - - public CharacterValidator(String missing) { - this.missingCharacter = getPixels(drawBitmap(missing)); - } - - private Bitmap drawBitmap(String text) { - Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ALPHA_8); - Canvas c = new Canvas(b); - c.drawText(text, 0, BITMAP_HEIGHT / 2, this.paint); - return b; - } - - private static byte[] getPixels(final Bitmap b) { - final int byteCount; - if (Versions.feature19Plus) { - byteCount = b.getAllocationByteCount(); - } else { - // Close enough for government work. - // Equivalent to getByteCount, but works on <12. - byteCount = b.getRowBytes() * b.getHeight(); - } - - final ByteBuffer buffer = ByteBuffer.allocate(byteCount); - try { - b.copyPixelsToBuffer(buffer); - } catch (RuntimeException e) { - // Android throws this if there's not enough space in the buffer. - // This should never occur, but if it does, we don't - // really care -- we probably don't need the entire image. - // This is awful. I apologize. - if ("Buffer not large enough for pixels".equals(e.getMessage())) { - return buffer.array(); - } - throw e; - } - - return buffer.array(); - } - - public boolean characterIsMissingInFont(String ch) { - byte[] rendered = getPixels(drawBitmap(ch)); - return Arrays.equals(rendered, missingCharacter); - } - } - - private volatile Locale entriesLocale; - private final CharacterValidator characterValidator; - - public LocaleListPreference(Context context) { - this(context, null); - } - - public LocaleListPreference(Context context, AttributeSet attributes) { - super(context, attributes); - - // Thus far, missing glyphs are replaced by whitespace, not a box - // or other Unicode codepoint. - this.characterValidator = new CharacterValidator(" "); - buildList(); - } - - private static final class LocaleDescriptor implements Comparable<LocaleDescriptor> { - // We use Locale.US here to ensure a stable ordering of entries. - private static final Collator COLLATOR = Collator.getInstance(Locale.US); - - public final String tag; - private final String nativeName; - - public LocaleDescriptor(String tag) { - this(Locales.parseLocaleCode(tag), tag); - } - - public LocaleDescriptor(Locale locale, String tag) { - this.tag = tag; - - final String displayName = locale.getDisplayName(locale); - if (TextUtils.isEmpty(displayName)) { - // There's nothing sane we can do. - Log.w(LOG_TAG, "Display name is empty. Using " + locale.toString()); - this.nativeName = locale.toString(); - return; - } - - // For now, uppercase the first character of LTR locale names. - // This is pretty much what Android does. This is a reasonable hack - // for Bug 1014602, but it won't generalize to all locales. - final byte directionality = Character.getDirectionality(displayName.charAt(0)); - if (directionality == Character.DIRECTIONALITY_LEFT_TO_RIGHT) { - this.nativeName = displayName.substring(0, 1).toUpperCase(locale) + - displayName.substring(1); - return; - } - - this.nativeName = displayName; - } - - public String getTag() { - return this.tag; - } - - public String getDisplayName() { - return this.nativeName; - } - - @Override - public String toString() { - return this.nativeName; - } - - - @Override - public int compareTo(LocaleDescriptor another) { - // We sort by name, so we use Collator. - return COLLATOR.compare(this.nativeName, another.nativeName); - } - - /** - * See Bug 1023451 Comment 10 for the research that led to - * this method. - * - * @return true if this locale can be used for displaying UI - * on this device without known issues. - */ - public boolean isUsable(CharacterValidator validator) { - if (Versions.preLollipop && this.tag.matches("[a-zA-Z]{3}.*")) { - // Earlier versions of Android can't load three-char locale code - // resources. - return false; - } - - // Oh, for Java 7 switch statements. - if (this.tag.equals("bn-IN")) { - // Bengali sometimes has an English label if the Bengali script - // is missing. This prevents us from simply checking character - // rendering for bn-IN; we'll get a false positive for "B", not "ব". - // - // This doesn't seem to affect other Bengali-script locales - // (below), which always have a label in native script. - if (!this.nativeName.startsWith("বাংলা")) { - // We're on an Android version that doesn't even have - // characters to say বাংলা. Definite failure. - return false; - } - } - - // These locales use a script that is often unavailable - // on common Android devices. Make sure we can show them. - // See documentation for CharacterValidator. - // Note that bn-IN is checked here even if it passed above. - if (this.tag.equals("or") || - this.tag.equals("my") || - this.tag.equals("pa-IN") || - this.tag.equals("gu-IN") || - this.tag.equals("bn-IN")) { - if (validator.characterIsMissingInFont(this.nativeName.substring(0, 1))) { - return false; - } - } - - return true; - } - } - - /** - * Not every locale we ship can be used on every device, due to - * font or rendering constraints. - * - * This method filters down the list before generating the descriptor array. - */ - private LocaleDescriptor[] getUsableLocales() { - Collection<String> shippingLocales = BrowserLocaleManager.getPackagedLocaleTags(getContext()); - - // Future: single-locale builds should be specified, too. - if (shippingLocales == null) { - final String fallbackTag = BrowserLocaleManager.getInstance().getFallbackLocaleTag(); - return new LocaleDescriptor[] { new LocaleDescriptor(fallbackTag) }; - } - - final int initialCount = shippingLocales.size(); - final Set<LocaleDescriptor> locales = new HashSet<LocaleDescriptor>(initialCount); - for (String tag : shippingLocales) { - final LocaleDescriptor descriptor = new LocaleDescriptor(tag); - - if (!descriptor.isUsable(this.characterValidator)) { - Log.w(LOG_TAG, "Skipping locale " + tag + " on this device."); - continue; - } - - locales.add(descriptor); - } - - final int usableCount = locales.size(); - final LocaleDescriptor[] descriptors = locales.toArray(new LocaleDescriptor[usableCount]); - Arrays.sort(descriptors, 0, usableCount); - return descriptors; - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - // The superclass will take care of persistence. - super.onDialogClosed(positiveResult); - - // Use this hook to try to fix up the environment ASAP. - // Do this so that the redisplayed fragment is inflated - // with the right locale. - final Locale selectedLocale = getSelectedLocale(); - final Context context = getContext(); - BrowserLocaleManager.getInstance().updateConfiguration(context, selectedLocale); - } - - private Locale getSelectedLocale() { - final String tag = getValue(); - if (tag == null || tag.equals("")) { - return Locale.getDefault(); - } - return Locales.parseLocaleCode(tag); - } - - @Override - public CharSequence getSummary() { - final String value = getValue(); - - if (TextUtils.isEmpty(value)) { - return getContext().getString(R.string.locale_system_default); - } - - // We can't trust super.getSummary() across locale changes, - // apparently, so let's do the same work. - return new LocaleDescriptor(value).getDisplayName(); - } - - private void buildList() { - final Locale currentLocale = Locale.getDefault(); - Log.d(LOG_TAG, "Building locales list. Current locale: " + currentLocale); - - if (currentLocale.equals(this.entriesLocale) && - getEntries() != null) { - Log.v(LOG_TAG, "No need to build list."); - return; - } - - final LocaleDescriptor[] descriptors = getUsableLocales(); - final int count = descriptors.length; - - this.entriesLocale = currentLocale; - - // We leave room for "System default". - final String[] entries = new String[count + 1]; - final String[] values = new String[count + 1]; - - entries[0] = getContext().getString(R.string.locale_system_default); - values[0] = ""; - - for (int i = 0; i < count; ++i) { - final String displayName = descriptors[i].getDisplayName(); - final String tag = descriptors[i].getTag(); - Log.v(LOG_TAG, displayName + " => " + tag); - entries[i + 1] = displayName; - values[i + 1] = tag; - } - - setEntries(entries); - setEntryValues(values); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/ModifiableHintPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/ModifiableHintPreference.java deleted file mode 100644 index c545472e2..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/ModifiableHintPreference.java +++ /dev/null @@ -1,67 +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 android.content.Context; -import android.graphics.drawable.Drawable; -import android.preference.Preference; -import android.text.Spanned; -import android.text.SpannableStringBuilder; -import android.text.style.ImageSpan; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -class ModifiableHintPreference extends Preference { - private static final String LOGTAG = "ModifiableHintPref"; - private final Context mContext; - - private final String MATCH_STRING = "%I"; - private final int RESID_TEXT_VIEW = R.id.label_search_hint; - private final int RESID_DRAWABLE = R.drawable.ab_add_search_engine; - private final double SCALE_FACTOR = 0.5; - - public ModifiableHintPreference(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - } - - public ModifiableHintPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mContext = context; - } - - @Override - protected View onCreateView(ViewGroup parent) { - View thisView = super.onCreateView(parent); - configurePreferenceView(thisView); - return thisView; - } - - private void configurePreferenceView(View view) { - TextView textView = (TextView) view.findViewById(RESID_TEXT_VIEW); - String searchHint = textView.getText().toString(); - - // Use an ImageSpan to include the "add search" icon in the Tip. - int imageSpanIndex = searchHint.indexOf(MATCH_STRING); - if (imageSpanIndex != -1) { - // Scale the resource. - Drawable drawable = mContext.getResources().getDrawable(RESID_DRAWABLE); - drawable.setBounds(0, 0, (int) (drawable.getIntrinsicWidth() * SCALE_FACTOR), - (int) (drawable.getIntrinsicHeight() * SCALE_FACTOR)); - - ImageSpan searchIcon = new ImageSpan(drawable); - final SpannableStringBuilder hintBuilder = new SpannableStringBuilder(searchHint); - - // Insert the image. - hintBuilder.setSpan(searchIcon, imageSpanIndex, imageSpanIndex + MATCH_STRING.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - textView.setText(hintBuilder, TextView.BufferType.SPANNABLE); - } - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java deleted file mode 100644 index 5749bf29d..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java +++ /dev/null @@ -1,271 +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.PrefUtils; -import org.mozilla.gecko.util.ThreadUtils; - -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 java.util.HashSet; -import java.util.Set; - -class MultiChoicePreference extends DialogPreference implements DialogInterface.OnMultiChoiceClickListener { - private static final String LOGTAG = "GeckoMultiChoicePreference"; - - private boolean mValues[]; - private boolean mPrevValues[]; - private CharSequence mEntryValues[]; - private CharSequence mEntries[]; - private CharSequence mInitialValues[]; - - public MultiChoicePreference(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiChoicePreference); - mEntries = a.getTextArray(R.styleable.MultiChoicePreference_entries); - mEntryValues = a.getTextArray(R.styleable.MultiChoicePreference_entryValues); - mInitialValues = a.getTextArray(R.styleable.MultiChoicePreference_initialValues); - a.recycle(); - - loadPersistedValues(); - } - - public MultiChoicePreference(Context context) { - this(context, null); - } - - /** - * Sets the human-readable entries to be shown in the list. This will be - * shown in subsequent dialogs. - * <p> - * Each entry must have a corresponding index in - * {@link #setEntryValues(CharSequence[])} and - * {@link #setInitialValues(CharSequence[])}. - * - * @param entries The entries. - */ - public void setEntries(CharSequence[] entries) { - mEntries = entries.clone(); - } - - /** - * @param entriesResId The entries array as a resource. - */ - public void setEntries(int entriesResId) { - setEntries(getContext().getResources().getTextArray(entriesResId)); - } - - /** - * Sets the preference values for preferences shown in the list. - * - * @param entryValues The entry values. - */ - public void setEntryValues(CharSequence[] entryValues) { - mEntryValues = entryValues.clone(); - loadPersistedValues(); - } - - /** - * Entry values define a separate pref for each row in the dialog. - * - * @param entryValuesResId The entryValues array as a resource. - */ - public void setEntryValues(int entryValuesResId) { - setEntryValues(getContext().getResources().getTextArray(entryValuesResId)); - } - - /** - * The array of initial entry values in this list. Each entryValue - * corresponds to an entryKey. These values are used if a) the preference - * isn't persisted, or b) the preference is persisted but hasn't yet been - * set. - * - * @param initialValues The entry values - */ - public void setInitialValues(CharSequence[] initialValues) { - mInitialValues = initialValues.clone(); - loadPersistedValues(); - } - - /** - * @param initialValuesResId The initialValues array as a resource. - */ - public void setInitialValues(int initialValuesResId) { - setInitialValues(getContext().getResources().getTextArray(initialValuesResId)); - } - - /** - * The list of translated strings corresponding to each preference. - * - * @return The array of entries. - */ - public CharSequence[] getEntries() { - return mEntries.clone(); - } - - /** - * The list of values corresponding to each preference. - * - * @return The array of values. - */ - public CharSequence[] getEntryValues() { - return mEntryValues.clone(); - } - - /** - * The list of initial values for each preference. Each string in this list - * should be either "true" or "false". - * - * @return The array of initial values. - */ - public CharSequence[] getInitialValues() { - 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) { - } - - @Override - protected void onPrepareDialogBuilder(Builder builder) { - if (mEntries == null || mInitialValues == null || mEntryValues == null) { - throw new IllegalStateException( - "MultiChoicePreference requires entries, entryValues, and initialValues arrays."); - } - - if (mEntries.length != mEntryValues.length || mEntries.length != mInitialValues.length) { - throw new IllegalStateException( - "MultiChoicePreference entries, entryValues, and initialValues arrays must be the same length"); - } - - builder.setMultiChoiceItems(mEntries, mValues, this); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - if (mPrevValues == null || mInitialValues == null) { - // Initialization is done asynchronously, so these values may not - // have been set before the dialog was closed. - return; - } - - if (!positiveResult) { - // user cancelled; reset checkbox values to their previous state - mValues = mPrevValues.clone(); - return; - } - - mPrevValues = mValues.clone(); - - if (!callChangeListener(getValues())) { - return; - } - - persist(); - } - - /* Persists the current data stored by this pref to SharedPreferences. */ - public boolean persist() { - if (isPersistent()) { - final SharedPreferences.Editor edit = GeckoSharedPrefs.forProfile(getContext()).edit(); - final boolean res = persist(edit); - edit.apply(); - 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).apply();; - 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); - } - - /** - * Loads persistent prefs from shared preferences. If the preferences - * 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]; - - if (entryCount != mEntries.length || entryCount != mEntryValues.length) { - throw new IllegalStateException( - "MultiChoicePreference entryValues and initialValues arrays must be the same length"); - } - - 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; - } - } - - mPrevValues = mValues.clone(); - } - }); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java deleted file mode 100644 index 580d613ca..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java +++ /dev/null @@ -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.apply(); - } 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); - } - } - -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreference.java deleted file mode 100644 index 337d9dd2f..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreference.java +++ /dev/null @@ -1,255 +0,0 @@ -/* 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.animation.PropertyAnimator; -import org.mozilla.gecko.animation.PropertyAnimator.Property; -import org.mozilla.gecko.animation.ViewHelper; -import org.mozilla.gecko.R; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.DialogInterface.OnShowListener; -import android.content.res.Resources; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -public class PanelsPreference extends CustomListPreference { - protected String LOGTAG = "PanelsPreference"; - - // Position state of this Preference in enclosing category. - private static final int STATE_IS_FIRST = 0; - private static final int STATE_IS_LAST = 1; - - /** - * Index of the context menu button for controlling display options. - * For (removable) Dynamic panels, this button removes the panel. - * For built-in panels, this button toggles showing or hiding the panel. - */ - private static final int INDEX_DISPLAY_BUTTON = 1; - private static final int INDEX_REORDER_BUTTON = 2; - - // Indices of buttons in context menu for reordering. - private static final int INDEX_MOVE_UP_BUTTON = 0; - private static final int INDEX_MOVE_DOWN_BUTTON = 1; - - private String LABEL_HIDE; - private String LABEL_SHOW; - - private View preferenceView; - protected boolean mIsHidden; - private final boolean mIsRemovable; - - private boolean mAnimate; - private static final int ANIMATION_DURATION_MS = 400; - - // State for reordering. - private int mPositionState = -1; - private final int mIndex; - - public PanelsPreference(Context context, CustomListCategory parentCategory, boolean isRemovable, int index, boolean animate) { - super(context, parentCategory); - mIsRemovable = isRemovable; - mIndex = index; - mAnimate = animate; - } - - @Override - protected int getPreferenceLayoutResource() { - return R.layout.preference_panels; - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - - // Override view handling so we can grey out "hidden" PanelPreferences. - view.setEnabled(!mIsHidden); - - if (view instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) view; - for (int i = 0; i < group.getChildCount(); i++) { - group.getChildAt(i).setEnabled(!mIsHidden); - } - preferenceView = group; - } - - if (mAnimate) { - ViewHelper.setAlpha(preferenceView, 0); - - final PropertyAnimator animator = new PropertyAnimator(ANIMATION_DURATION_MS); - animator.attach(preferenceView, Property.ALPHA, 1); - animator.start(); - - // Clear animate flag. - mAnimate = false; - } - } - - @Override - protected String[] createDialogItems() { - final Resources res = getContext().getResources(); - final String labelReorder = res.getString(R.string.pref_panels_reorder); - - if (mIsRemovable) { - return new String[] { LABEL_SET_AS_DEFAULT, LABEL_REMOVE, labelReorder }; - } - - // Built-in panels can't be removed, so use show/hide options. - LABEL_HIDE = res.getString(R.string.pref_panels_hide); - LABEL_SHOW = res.getString(R.string.pref_panels_show); - - return new String[] { LABEL_SET_AS_DEFAULT, LABEL_HIDE, labelReorder }; - } - - @Override - public void setIsDefault(boolean isDefault) { - mIsDefault = isDefault; - if (isDefault) { - setSummary(LABEL_IS_DEFAULT); - if (mIsHidden) { - // Unhide the panel if it's being set as the default. - setHidden(false); - } - } else { - setSummary(""); - } - } - - @Override - protected void onDialogIndexClicked(int index) { - switch (index) { - case INDEX_SET_DEFAULT_BUTTON: - mParentCategory.setDefault(this); - break; - - case INDEX_DISPLAY_BUTTON: - // Handle display options for the panel. - if (mIsRemovable) { - // For removable panels, the button displays text for removing the panel. - mParentCategory.uninstall(this); - } else { - // Otherwise, the button toggles between text for showing or hiding the panel. - ((PanelsPreferenceCategory) mParentCategory).setHidden(this, !mIsHidden); - } - break; - - case INDEX_REORDER_BUTTON: - // Display dialog for changing preference order. - final Dialog orderDialog = makeReorderDialog(); - orderDialog.show(); - break; - - default: - Log.w(LOGTAG, "Selected index out of range: " + index); - } - } - - @Override - protected void configureShownDialog() { - super.configureShownDialog(); - - // Handle Show/Hide buttons. - if (!mIsRemovable) { - final TextView hideButton = (TextView) mDialog.getListView().getChildAt(INDEX_DISPLAY_BUTTON); - hideButton.setText(mIsHidden ? LABEL_SHOW : LABEL_HIDE); - } - } - - - private Dialog makeReorderDialog() { - final AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - - final Resources res = getContext().getResources(); - final String labelUp = res.getString(R.string.pref_panels_move_up); - final String labelDown = res.getString(R.string.pref_panels_move_down); - - builder.setTitle(getTitle()); - builder.setItems(new String[] { labelUp, labelDown }, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int index) { - dialog.dismiss(); - switch (index) { - case INDEX_MOVE_UP_BUTTON: - ((PanelsPreferenceCategory) mParentCategory).moveUp(PanelsPreference.this); - break; - - case INDEX_MOVE_DOWN_BUTTON: - ((PanelsPreferenceCategory) mParentCategory).moveDown(PanelsPreference.this); - break; - } - } - }); - - final Dialog dialog = builder.create(); - dialog.setOnShowListener(new OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - setReorderItemsEnabled(dialog); - } - }); - - return dialog; - } - - public void setIsFirst() { - mPositionState = STATE_IS_FIRST; - } - - public void setIsLast() { - mPositionState = STATE_IS_LAST; - } - - /** - * Configure enabled state of the reorder dialog, which must be done after the dialog is shown. - * @param dialog Dialog to configure - */ - private void setReorderItemsEnabled(DialogInterface dialog) { - // Update button enabled-ness for reordering. - switch (mPositionState) { - case STATE_IS_FIRST: - final TextView itemUp = (TextView) ((AlertDialog) dialog).getListView().getChildAt(INDEX_MOVE_UP_BUTTON); - itemUp.setEnabled(false); - // Disable clicks to this view. - itemUp.setOnClickListener(null); - break; - - case STATE_IS_LAST: - final TextView itemDown = (TextView) ((AlertDialog) dialog).getListView().getChildAt(INDEX_MOVE_DOWN_BUTTON); - itemDown.setEnabled(false); - // Disable clicks to this view. - itemDown.setOnClickListener(null); - break; - - default: - // Do nothing. - break; - } - } - - public void setHidden(boolean toHide) { - if (toHide) { - setIsDefault(false); - } - - if (mIsHidden != toHide) { - mIsHidden = toHide; - notifyChanged(); - } - } - - public boolean isHidden() { - return mIsHidden; - } - - public int getIndex() { - return mIndex; - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreferenceCategory.java b/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreferenceCategory.java deleted file mode 100644 index d44b6eaa9..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/PanelsPreferenceCategory.java +++ /dev/null @@ -1,261 +0,0 @@ -/* 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.GeckoSharedPrefs; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.TelemetryContract.Method; -import org.mozilla.gecko.home.HomeConfig; -import org.mozilla.gecko.home.HomeConfig.PanelConfig; -import org.mozilla.gecko.home.HomeConfig.State; -import org.mozilla.gecko.util.ThreadUtils; -import org.mozilla.gecko.util.UIAsyncTask; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; - -public class PanelsPreferenceCategory extends CustomListCategory { - public static final String LOGTAG = "PanelsPrefCategory"; - - protected HomeConfig mHomeConfig; - protected HomeConfig.Editor mConfigEditor; - - protected UIAsyncTask.WithoutParams<State> mLoadTask; - - public PanelsPreferenceCategory(Context context) { - super(context); - initConfig(context); - } - - public PanelsPreferenceCategory(Context context, AttributeSet attrs) { - super(context, attrs); - initConfig(context); - } - - public PanelsPreferenceCategory(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initConfig(context); - } - - protected void initConfig(Context context) { - mHomeConfig = HomeConfig.getDefault(context); - } - - @Override - public void onAttachedToActivity() { - super.onAttachedToActivity(); - - loadHomeConfig(null); - } - - /** - * Load the Home Panels config and populate the preferences screen and maintain local state. - */ - private void loadHomeConfig(final String animatePanelId) { - mLoadTask = new UIAsyncTask.WithoutParams<State>(ThreadUtils.getBackgroundHandler()) { - @Override - public HomeConfig.State doInBackground() { - return mHomeConfig.load(); - } - - @Override - public void onPostExecute(HomeConfig.State configState) { - mConfigEditor = configState.edit(); - displayHomeConfig(configState, animatePanelId); - } - }; - mLoadTask.execute(); - } - - /** - * Simplified refresh of Home Panels when there is no state to be persisted. - */ - public void refresh() { - refresh(null, null); - } - - /** - * Refresh the Home Panels list and animate a panel, if specified. - * If null, load from HomeConfig. - * - * @param State HomeConfig.State to rebuild Home Panels list from. - * @param String panelId of panel to be animated. - */ - public void refresh(State state, String animatePanelId) { - // Clear all the existing home panels. - removeAll(); - - if (state == null) { - loadHomeConfig(animatePanelId); - } else { - displayHomeConfig(state, animatePanelId); - } - } - - private void displayHomeConfig(HomeConfig.State configState, String animatePanelId) { - int index = 0; - for (PanelConfig panelConfig : configState) { - final boolean isRemovable = panelConfig.isDynamic(); - - // Create and add the pref. - final String panelId = panelConfig.getId(); - final boolean animate = TextUtils.equals(animatePanelId, panelId); - - final PanelsPreference pref = new PanelsPreference(getContext(), PanelsPreferenceCategory.this, isRemovable, index, animate); - pref.setTitle(panelConfig.getTitle()); - pref.setKey(panelConfig.getId()); - // XXX: Pull icon from PanelInfo. - addPreference(pref); - - if (panelConfig.isDisabled()) { - pref.setHidden(true); - } - - index++; - } - - setPositionState(); - setDefaultFromConfig(); - } - - private void setPositionState() { - final int prefCount = getPreferenceCount(); - - // Pass in position state to first and last preference. - final PanelsPreference firstPref = (PanelsPreference) getPreference(0); - firstPref.setIsFirst(); - - final PanelsPreference lastPref = (PanelsPreference) getPreference(prefCount - 1); - lastPref.setIsLast(); - } - - private void setDefaultFromConfig() { - final String defaultPanelId = mConfigEditor.getDefaultPanelId(); - if (defaultPanelId == null) { - mDefaultReference = null; - return; - } - - final int prefCount = getPreferenceCount(); - - for (int i = 0; i < prefCount; i++) { - final PanelsPreference pref = (PanelsPreference) getPreference(i); - - if (defaultPanelId.equals(pref.getKey())) { - super.setDefault(pref); - break; - } - } - } - - @Override - public void setDefault(CustomListPreference pref) { - super.setDefault(pref); - - final String id = pref.getKey(); - - final String defaultPanelId = mConfigEditor.getDefaultPanelId(); - if (defaultPanelId != null && defaultPanelId.equals(id)) { - return; - } - - updateVisibilityPrefsForPanel(id, true); - - mConfigEditor.setDefault(id); - mConfigEditor.apply(); - - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_SET_DEFAULT, Method.DIALOG, id); - } - - @Override - protected void onPrepareForRemoval() { - super.onPrepareForRemoval(); - if (mLoadTask != null) { - mLoadTask.cancel(); - } - } - - @Override - public void uninstall(CustomListPreference pref) { - final String id = pref.getKey(); - mConfigEditor.uninstall(id); - mConfigEditor.apply(); - - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_REMOVE, Method.DIALOG, id); - - super.uninstall(pref); - } - - public void moveUp(PanelsPreference pref) { - final int panelIndex = pref.getIndex(); - if (panelIndex > 0) { - final String panelKey = pref.getKey(); - mConfigEditor.moveTo(panelKey, panelIndex - 1); - final State state = mConfigEditor.apply(); - - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_MOVE, Method.DIALOG, panelKey); - - refresh(state, panelKey); - } - } - - public void moveDown(PanelsPreference pref) { - final int panelIndex = pref.getIndex(); - if (panelIndex < getPreferenceCount() - 1) { - final String panelKey = pref.getKey(); - mConfigEditor.moveTo(panelKey, panelIndex + 1); - final State state = mConfigEditor.apply(); - - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_MOVE, Method.DIALOG, panelKey); - - refresh(state, panelKey); - } - } - - /** - * Update the hide/show state of the preference and save the HomeConfig - * changes. - * - * @param pref Preference to update - * @param toHide New hidden state of the preference - */ - protected void setHidden(PanelsPreference pref, boolean toHide) { - final String id = pref.getKey(); - mConfigEditor.setDisabled(id, toHide); - mConfigEditor.apply(); - - if (toHide) { - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_HIDE, Method.DIALOG, id); - } else { - Telemetry.sendUIEvent(TelemetryContract.Event.PANEL_SHOW, Method.DIALOG, id); - } - - updateVisibilityPrefsForPanel(id, !toHide); - - pref.setHidden(toHide); - setDefaultFromConfig(); - } - - /** - * When the default panel is removed or disabled, find an enabled panel - * if possible and set it as mDefaultReference. - */ - @Override - protected void setFallbackDefault() { - setDefaultFromConfig(); - } - - private void updateVisibilityPrefsForPanel(String panelId, boolean toShow) { - if (HomeConfig.getIdForBuiltinPanelType(HomeConfig.PanelType.BOOKMARKS).equals(panelId)) { - GeckoSharedPrefs.forProfile(getContext()).edit().putBoolean(HomeConfig.PREF_KEY_BOOKMARKS_PANEL_ENABLED, toShow).apply(); - } - - if (HomeConfig.getIdForBuiltinPanelType(HomeConfig.PanelType.COMBINED_HISTORY).equals(panelId)) { - GeckoSharedPrefs.forProfile(getContext()).edit().putBoolean(HomeConfig.PREF_KEY_HISTORY_PANEL_ENABLED, toShow).apply(); - } - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/PrivateDataPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/PrivateDataPreference.java deleted file mode 100644 index 61eff98e7..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/PrivateDataPreference.java +++ /dev/null @@ -1,67 +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.GeckoAppShell; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; - -import org.json.JSONException; -import org.json.JSONObject; -import org.mozilla.gecko.icons.storage.DiskStorage; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Set; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; - -class PrivateDataPreference extends MultiPrefMultiChoicePreference { - private static final String LOGTAG = "GeckoPrivateDataPreference"; - private static final String PREF_KEY_PREFIX = "private.data."; - - public PrivateDataPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - - if (!positiveResult) { - return; - } - - Telemetry.sendUIEvent(TelemetryContract.Event.SANITIZE, TelemetryContract.Method.DIALOG, "settings"); - - final Set<String> values = getValues(); - final JSONObject json = new JSONObject(); - - for (String value : values) { - // 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()); - try { - json.put(key, true); - } catch (JSONException e) { - Log.e(LOGTAG, "JSON error", e); - } - } - - if (values.contains("private.data.offlineApps")) { - // Remove all icons from storage if removing "Offline website data" was selected. - DiskStorage.get(getContext()).evictAll(); - } - - // clear private data in gecko - GeckoAppShell.notifyObservers("Sanitize:ClearData", json.toString()); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java deleted file mode 100644 index 3ba80b562..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/SearchEnginePreference.java +++ /dev/null @@ -1,183 +0,0 @@ -/* 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.json.JSONException; -import org.json.JSONObject; -import org.mozilla.gecko.R; -import org.mozilla.gecko.SnackbarBuilder; -import org.mozilla.gecko.icons.IconCallback; -import org.mozilla.gecko.icons.IconDescriptor; -import org.mozilla.gecko.icons.IconResponse; -import org.mozilla.gecko.icons.Icons; -import org.mozilla.gecko.widget.FaviconView; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.support.design.widget.Snackbar; -import android.text.SpannableString; -import android.util.Log; -import android.view.View; - -/** - * Represents an element in the list of search engines on the preferences menu. - */ -public class SearchEnginePreference extends CustomListPreference { - protected String LOGTAG = "SearchEnginePreference"; - - protected static final int INDEX_REMOVE_BUTTON = 1; - - // The icon to display in the prompt when clicked. - private BitmapDrawable mPromptIcon; - - // The bitmap backing the drawable above - needed separately for the FaviconView. - private Bitmap mIconBitmap; - private final Object bitmapLock = new Object(); - - private FaviconView mFaviconView; - - // Search engine identifier specified by the gecko search service. This will be "other" - // for engines that are not shipped with the app. - private String mIdentifier; - - public SearchEnginePreference(Context context, SearchPreferenceCategory parentCategory) { - super(context, parentCategory); - } - - /** - * Called by Android when we're bound to the custom view. Allows us to set the custom properties - * of our custom view elements as we desire (We can now use findViewById on them). - * - * @param view The view instance for this Preference object. - */ - @Override - protected void onBindView(View view) { - super.onBindView(view); - - // We synchronise to avoid a race condition between this and the favicon loading callback in - // setSearchEngineFromJSON. - synchronized (bitmapLock) { - // Set the icon in the FaviconView. - mFaviconView = ((FaviconView) view.findViewById(R.id.search_engine_icon)); - - if (mIconBitmap != null) { - mFaviconView.updateAndScaleImage(IconResponse.create(mIconBitmap)); - } - } - } - - @Override - protected int getPreferenceLayoutResource() { - return R.layout.preference_search_engine; - } - - /** - * Returns the strings to be displayed in the dialog. - */ - @Override - protected String[] createDialogItems() { - return new String[] { LABEL_SET_AS_DEFAULT, - LABEL_REMOVE }; - } - - @Override - public void showDialog() { - // If this is the last engine, then we are the default, and none of the options - // on this menu can do anything. - if (mParentCategory.getPreferenceCount() == 1) { - Activity activity = (Activity) getContext(); - - SnackbarBuilder.builder(activity) - .message(R.string.pref_search_last_toast) - .duration(Snackbar.LENGTH_LONG) - .buildAndShow(); - - return; - } - - super.showDialog(); - } - - @Override - protected void configureDialogBuilder(AlertDialog.Builder builder) { - // Copy the icon from this object to the prompt we produce. We lazily create the drawable, - // as the user may not ever actually tap this object. - if (mPromptIcon == null && mIconBitmap != null) { - mPromptIcon = new BitmapDrawable(getContext().getResources(), mFaviconView.getBitmap()); - } - - builder.setIcon(mPromptIcon); - } - - @Override - protected void onDialogIndexClicked(int index) { - switch (index) { - case INDEX_SET_DEFAULT_BUTTON: - mParentCategory.setDefault(this); - break; - - case INDEX_REMOVE_BUTTON: - mParentCategory.uninstall(this); - break; - - default: - Log.w(LOGTAG, "Selected index out of range."); - break; - } - } - - /** - * @return Identifier of built-in search engine, or "other" if engine is not built-in. - */ - public String getIdentifier() { - return mIdentifier; - } - - /** - * Configure this Preference object from the Gecko search engine JSON object. - * @param geckoEngineJSON The Gecko-formatted JSON object representing the search engine. - * @throws JSONException If the JSONObject is invalid. - */ - public void setSearchEngineFromJSON(JSONObject geckoEngineJSON) throws JSONException { - mIdentifier = geckoEngineJSON.getString("identifier"); - - // A null JS value gets converted into a string. - if (mIdentifier.equals("null")) { - mIdentifier = "other"; - } - - final String engineName = geckoEngineJSON.getString("name"); - final SpannableString titleSpannable = new SpannableString(engineName); - - setTitle(titleSpannable); - - final String iconURI = geckoEngineJSON.getString("iconURI"); - // Keep a reference to the bitmap - we'll need it later in onBindView. - try { - Icons.with(getContext()) - .pageUrl(mIdentifier) - .icon(IconDescriptor.createGenericIcon(iconURI)) - .privileged(true) - .build() - .execute(new IconCallback() { - @Override - public void onIconResponse(IconResponse response) { - mIconBitmap = response.getBitmap(); - - if (mFaviconView != null) { - mFaviconView.updateAndScaleImage(response); - } - } - }); - } catch (IllegalArgumentException e) { - Log.e(LOGTAG, "IllegalArgumentException creating Bitmap. Most likely a zero-length bitmap.", e); - } catch (NullPointerException e) { - Log.e(LOGTAG, "NullPointerException creating Bitmap. Most likely a zero-length bitmap.", e); - } - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/SearchPreferenceCategory.java b/mobile/android/base/java/org/mozilla/gecko/preferences/SearchPreferenceCategory.java deleted file mode 100644 index 47db8b9b0..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/SearchPreferenceCategory.java +++ /dev/null @@ -1,145 +0,0 @@ -/* 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.preference.Preference; -import android.util.AttributeSet; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import org.mozilla.gecko.EventDispatcher; -import org.mozilla.gecko.GeckoApp; -import org.mozilla.gecko.GeckoAppShell; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.TelemetryContract.Method; -import org.mozilla.gecko.util.GeckoEventListener; -import org.mozilla.gecko.util.ThreadUtils; - -public class SearchPreferenceCategory extends CustomListCategory implements GeckoEventListener { - public static final String LOGTAG = "SearchPrefCategory"; - - public SearchPreferenceCategory(Context context) { - super(context); - } - - public SearchPreferenceCategory(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public SearchPreferenceCategory(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onAttachedToActivity() { - super.onAttachedToActivity(); - - // Register for SearchEngines messages and request list of search engines from Gecko. - GeckoApp.getEventDispatcher().registerGeckoThreadListener(this, "SearchEngines:Data"); - GeckoAppShell.notifyObservers("SearchEngines:GetVisible", null); - } - - @Override - protected void onPrepareForRemoval() { - super.onPrepareForRemoval(); - - GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this, "SearchEngines:Data"); - } - - @Override - public void setDefault(CustomListPreference item) { - super.setDefault(item); - - sendGeckoEngineEvent("SearchEngines:SetDefault", item.getTitle().toString()); - - final String identifier = ((SearchEnginePreference) item).getIdentifier(); - Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH_SET_DEFAULT, Method.DIALOG, identifier); - } - - @Override - public void uninstall(CustomListPreference item) { - super.uninstall(item); - - sendGeckoEngineEvent("SearchEngines:Remove", item.getTitle().toString()); - - final String identifier = ((SearchEnginePreference) item).getIdentifier(); - Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH_REMOVE, Method.DIALOG, identifier); - } - - @Override - public void handleMessage(String event, final JSONObject data) { - if (event.equals("SearchEngines:Data")) { - // Parse engines array from JSON. - JSONArray engines; - try { - engines = data.getJSONArray("searchEngines"); - } catch (JSONException e) { - Log.e(LOGTAG, "Unable to decode search engine data from Gecko.", e); - return; - } - - // Clear the preferences category from this thread. - this.removeAll(); - - // Create an element in this PreferenceCategory for each engine. - for (int i = 0; i < engines.length(); i++) { - try { - final JSONObject engineJSON = engines.getJSONObject(i); - - final SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this); - enginePreference.setSearchEngineFromJSON(engineJSON); - enginePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - SearchEnginePreference sPref = (SearchEnginePreference) preference; - // Display the configuration dialog associated with the tapped engine. - sPref.showDialog(); - return true; - } - }); - - addPreference(enginePreference); - - // The first element in the array is the default engine. - if (i == 0) { - // We set this here, not in setSearchEngineFromJSON, because it allows us to - // keep a reference to the default engine to use when the AlertDialog - // callbacks are used. - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - enginePreference.setIsDefault(true); - } - }); - mDefaultReference = enginePreference; - } - } catch (JSONException e) { - Log.e(LOGTAG, "JSONException parsing engine at index " + i, e); - } - } - } - } - - /** - * Helper method to send a particular event string to Gecko with an associated engine name. - * @param event The type of event to send. - * @param engine The engine to which the event relates. - */ - private void sendGeckoEngineEvent(String event, String engineName) { - JSONObject json = new JSONObject(); - try { - json.put("engine", engineName); - } catch (JSONException e) { - Log.e(LOGTAG, "JSONException creating search engine configuration change message for Gecko.", e); - return; - } - GeckoAppShell.notifyObservers(event, json.toString()); - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/SetHomepagePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/SetHomepagePreference.java deleted file mode 100644 index 55be702c4..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/SetHomepagePreference.java +++ /dev/null @@ -1,124 +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.preferences; - -import org.mozilla.gecko.AboutPages; -import org.mozilla.gecko.GeckoSharedPrefs; -import org.mozilla.gecko.R; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.DialogPreference; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.RadioButton; -import android.widget.RadioGroup; - -public class SetHomepagePreference extends DialogPreference { - private static final String DEFAULT_HOMEPAGE = AboutPages.HOME; - - private final SharedPreferences prefs; - - private RadioGroup homepageLayout; - private RadioButton defaultRadio; - private RadioButton userAddressRadio; - private EditText homepageEditText; - - // This is the url that 1) was loaded from prefs or, 2) stored - // when the user pressed the "default homepage" checkbox. - private String storedUrl; - - public SetHomepagePreference(final Context context, final AttributeSet attrs) { - super(context, attrs); - prefs = GeckoSharedPrefs.forProfile(context); - } - - @Override - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { - // Without this GB devices have a black background to the dialog. - builder.setInverseBackgroundForced(true); - } - - @Override - protected void onBindDialogView(final View view) { - super.onBindDialogView(view); - - homepageLayout = (RadioGroup) view.findViewById(R.id.homepage_layout); - defaultRadio = (RadioButton) view.findViewById(R.id.radio_default); - userAddressRadio = (RadioButton) view.findViewById(R.id.radio_user_address); - homepageEditText = (EditText) view.findViewById(R.id.edittext_user_address); - - storedUrl = prefs.getString(GeckoPreferences.PREFS_HOMEPAGE, DEFAULT_HOMEPAGE); - - homepageLayout.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(final RadioGroup radioGroup, final int checkedId) { - if (checkedId == R.id.radio_user_address) { - homepageEditText.setVisibility(View.VISIBLE); - openKeyboardAndSelectAll(getContext(), homepageEditText); - } else { - homepageEditText.setVisibility(View.GONE); - } - } - }); - setUIState(storedUrl); - } - - private void setUIState(final String url) { - if (isUrlDefaultHomepage(url)) { - defaultRadio.setChecked(true); - } else { - userAddressRadio.setChecked(true); - homepageEditText.setText(url); - } - } - - private boolean isUrlDefaultHomepage(final String url) { - return TextUtils.isEmpty(url) || DEFAULT_HOMEPAGE.equals(url); - } - - private static void openKeyboardAndSelectAll(final Context context, final View viewToFocus) { - viewToFocus.requestFocus(); - viewToFocus.post(new Runnable() { - @Override - public void run() { - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(viewToFocus, InputMethodManager.SHOW_IMPLICIT); - // android:selectAllOnFocus doesn't work for the initial focus: - // I'm not sure why. We manually selectAll instead. - if (viewToFocus instanceof EditText) { - ((EditText) viewToFocus).selectAll(); - } - } - }); - } - - @Override - protected void onDialogClosed(final boolean positiveResult) { - super.onDialogClosed(positiveResult); - if (positiveResult) { - final SharedPreferences.Editor editor = prefs.edit(); - final String homePageEditTextValue = homepageEditText.getText().toString(); - final String newPrefValue; - if (homepageLayout.getCheckedRadioButtonId() == R.id.radio_default || - isUrlDefaultHomepage(homePageEditTextValue)) { - newPrefValue = ""; - editor.remove(GeckoPreferences.PREFS_HOMEPAGE); - } else { - newPrefValue = homePageEditTextValue; - editor.putString(GeckoPreferences.PREFS_HOMEPAGE, newPrefValue); - } - editor.apply(); - - if (getOnPreferenceChangeListener() != null) { - getOnPreferenceChangeListener().onPreferenceChange(this, newPrefValue); - } - } - } -} diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/SyncPreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/SyncPreference.java deleted file mode 100644 index 350ac8fc0..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/preferences/SyncPreference.java +++ /dev/null @@ -1,103 +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.content.Intent; -import android.preference.Preference; -import android.text.TextUtils; -import android.util.AttributeSet; - -import com.squareup.picasso.Picasso; -import com.squareup.picasso.Target; - -import org.mozilla.gecko.AppConstants; -import org.mozilla.gecko.R; -import org.mozilla.gecko.Telemetry; -import org.mozilla.gecko.TelemetryContract; -import org.mozilla.gecko.TelemetryContract.Method; -import org.mozilla.gecko.fxa.FxAccountConstants; -import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity; -import org.mozilla.gecko.fxa.activities.PicassoPreferenceIconTarget; -import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; -import org.mozilla.gecko.sync.ExtendedJSONObject; -import org.mozilla.gecko.util.ThreadUtils; - -class SyncPreference extends Preference { - private final Context mContext; - private final Target profileAvatarTarget; - - public SyncPreference(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - final float cornerRadius = mContext.getResources().getDimension(R.dimen.fxaccount_profile_image_width) / 2; - profileAvatarTarget = new PicassoPreferenceIconTarget(mContext.getResources(), this, cornerRadius); - } - - private void launchFxASetup() { - final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED); - intent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - mContext.startActivity(intent); - } - - public void update(final AndroidFxAccount fxAccount) { - if (fxAccount == null) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - setTitle(R.string.pref_sync); - setSummary(R.string.pref_sync_summary); - // Cancel any pending task. - Picasso.with(mContext).cancelRequest(profileAvatarTarget); - // Clear previously set icon. - // Bug 1312719 - IconDrawable is prior to IconResId, drawable must be set null before setIcon(resId) - // http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/preference/Preference.java#562 - setIcon(null); - setIcon(R.drawable.sync_avatar_default); - } - }); - return; - } - - // Update title from account email. - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - setTitle(fxAccount.getEmail()); - setSummary(""); - } - }); - - final ExtendedJSONObject profileJSON = fxAccount.getProfileJSON(); - if (profileJSON == null) { - return; - } - - // Avatar URI empty, return early. - final String avatarURI = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_AVATAR); - if (TextUtils.isEmpty(avatarURI)) { - return; - } - - Picasso.with(mContext) - .load(avatarURI) - .centerInside() - .resizeDimen(R.dimen.fxaccount_profile_image_width, R.dimen.fxaccount_profile_image_height) - .placeholder(R.drawable.sync_avatar_default) - .error(R.drawable.sync_avatar_default) - .into(profileAvatarTarget); - } - - @Override - protected void onClick() { - // Launch the FxA "Get started" activity, which will dispatch to the - // right location. - launchFxASetup(); - Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.SETTINGS, "sync_setup"); - } -} |