mobile/android/base/preferences/GeckoPreferences.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/preferences/GeckoPreferences.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,947 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko.preferences;
    1.10 +
    1.11 +import java.util.ArrayList;
    1.12 +import java.util.List;
    1.13 +
    1.14 +import org.json.JSONObject;
    1.15 +import org.mozilla.gecko.AppConstants;
    1.16 +import org.mozilla.gecko.DataReportingNotification;
    1.17 +import org.mozilla.gecko.GeckoActivityStatus;
    1.18 +import org.mozilla.gecko.GeckoApp;
    1.19 +import org.mozilla.gecko.GeckoAppShell;
    1.20 +import org.mozilla.gecko.GeckoApplication;
    1.21 +import org.mozilla.gecko.GeckoEvent;
    1.22 +import org.mozilla.gecko.GeckoProfile;
    1.23 +import org.mozilla.gecko.GeckoSharedPrefs;
    1.24 +import org.mozilla.gecko.PrefsHelper;
    1.25 +import org.mozilla.gecko.R;
    1.26 +import org.mozilla.gecko.background.announcements.AnnouncementsConstants;
    1.27 +import org.mozilla.gecko.background.common.GlobalConstants;
    1.28 +import org.mozilla.gecko.background.healthreport.HealthReportConstants;
    1.29 +import org.mozilla.gecko.home.HomePanelPicker;
    1.30 +import org.mozilla.gecko.util.GeckoEventListener;
    1.31 +import org.mozilla.gecko.util.ThreadUtils;
    1.32 +
    1.33 +import android.app.Activity;
    1.34 +import android.app.AlertDialog;
    1.35 +import android.app.Dialog;
    1.36 +import android.app.Fragment;
    1.37 +import android.app.NotificationManager;
    1.38 +import android.content.Context;
    1.39 +import android.content.DialogInterface;
    1.40 +import android.content.Intent;
    1.41 +import android.content.SharedPreferences;
    1.42 +import android.os.Build;
    1.43 +import android.os.Bundle;
    1.44 +import android.preference.CheckBoxPreference;
    1.45 +import android.preference.EditTextPreference;
    1.46 +import android.preference.ListPreference;
    1.47 +import android.preference.Preference;
    1.48 +import android.preference.Preference.OnPreferenceChangeListener;
    1.49 +import android.preference.Preference.OnPreferenceClickListener;
    1.50 +import android.preference.PreferenceActivity;
    1.51 +import android.preference.PreferenceGroup;
    1.52 +import android.preference.PreferenceScreen;
    1.53 +import android.preference.TwoStatePreference;
    1.54 +import android.text.Editable;
    1.55 +import android.text.InputType;
    1.56 +import android.text.TextUtils;
    1.57 +import android.text.TextWatcher;
    1.58 +import android.util.Log;
    1.59 +import android.view.MenuItem;
    1.60 +import android.view.View;
    1.61 +import android.widget.AdapterView;
    1.62 +import android.widget.EditText;
    1.63 +import android.widget.LinearLayout;
    1.64 +import android.widget.ListAdapter;
    1.65 +import android.widget.ListView;
    1.66 +import android.widget.Toast;
    1.67 +
    1.68 +public class GeckoPreferences
    1.69 +    extends PreferenceActivity
    1.70 +    implements OnPreferenceChangeListener, GeckoEventListener, GeckoActivityStatus
    1.71 +{
    1.72 +    private static final String LOGTAG = "GeckoPreferences";
    1.73 +
    1.74 +    private static final String NON_PREF_PREFIX = "android.not_a_preference.";
    1.75 +    public static final String INTENT_EXTRA_RESOURCES = "resource";
    1.76 +    public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled";
    1.77 +
    1.78 +    private static boolean sIsCharEncodingEnabled = false;
    1.79 +    private boolean mInitialized = false;
    1.80 +    private int mPrefsRequestId = 0;
    1.81 +    private PanelsPreferenceCategory mPanelsPreferenceCategory;
    1.82 +
    1.83 +    // These match keys in resources/xml*/preferences*.xml
    1.84 +    private static final String PREFS_SEARCH_RESTORE_DEFAULTS = NON_PREF_PREFIX + "search.restore_defaults";
    1.85 +    private static final String PREFS_HOME_ADD_PANEL = NON_PREF_PREFIX + "home.add_panel";
    1.86 +    private static final String PREFS_ANNOUNCEMENTS_ENABLED = NON_PREF_PREFIX + "privacy.announcements.enabled";
    1.87 +    private static final String PREFS_DATA_REPORTING_PREFERENCES = NON_PREF_PREFIX + "datareporting.preferences";
    1.88 +    private static final String PREFS_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
    1.89 +    private static final String PREFS_CRASHREPORTER_ENABLED = "datareporting.crashreporter.submitEnabled";
    1.90 +    private static final String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
    1.91 +    private static final String PREFS_MP_ENABLED = "privacy.masterpassword.enabled";
    1.92 +    private static final String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload";
    1.93 +    private static final String PREFS_GEO_REPORTING = "app.geo.reportdata";
    1.94 +    private static final String PREFS_GEO_LEARN_MORE = NON_PREF_PREFIX + "geo.learn_more";
    1.95 +    private static final String PREFS_HEALTHREPORT_LINK = NON_PREF_PREFIX + "healthreport.link";
    1.96 +    private static final String PREFS_DEVTOOLS_REMOTE_ENABLED = "devtools.debugger.remote-enabled";
    1.97 +    private static final String PREFS_DISPLAY_REFLOW_ON_ZOOM = "browser.zoom.reflowOnZoom";
    1.98 +    private static final String PREFS_SYNC = NON_PREF_PREFIX + "sync";
    1.99 +
   1.100 +    public static final String PREFS_RESTORE_SESSION = NON_PREF_PREFIX + "restoreSession3";
   1.101 +
   1.102 +    // These values are chosen to be distinct from other Activity constants.
   1.103 +    private static final int REQUEST_CODE_PREF_SCREEN = 5;
   1.104 +    private static final int RESULT_CODE_EXIT_SETTINGS = 6;
   1.105 +
   1.106 +    @Override
   1.107 +    protected void onCreate(Bundle savedInstanceState) {
   1.108 +
   1.109 +        // For Android v11+ where we use Fragments (v11+ only due to bug 866352),
   1.110 +        // check that PreferenceActivity.EXTRA_SHOW_FRAGMENT has been set
   1.111 +        // (or set it) before super.onCreate() is called so Android can display
   1.112 +        // the correct Fragment resource.
   1.113 +
   1.114 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
   1.115 +            !getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
   1.116 +            // Set up the default fragment if there is no explicit fragment to show.
   1.117 +            setupTopLevelFragmentIntent();
   1.118 +        }
   1.119 +
   1.120 +        super.onCreate(savedInstanceState);
   1.121 +
   1.122 +        // Use setResourceToOpen to specify these extras.
   1.123 +        Bundle intentExtras = getIntent().getExtras();
   1.124 +
   1.125 +        // For versions of Android lower than Honeycomb, use xml resources instead of
   1.126 +        // Fragments because of an Android bug in ActionBar (described in bug 866352 and
   1.127 +        // fixed in bug 833625).
   1.128 +        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
   1.129 +            // Write prefs to our custom GeckoSharedPrefs file.
   1.130 +            getPreferenceManager().setSharedPreferencesName(GeckoSharedPrefs.APP_PREFS_NAME);
   1.131 +
   1.132 +            int res = 0;
   1.133 +            if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
   1.134 +                // Fetch resource id from intent.
   1.135 +                String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES);
   1.136 +                if (resourceName != null) {
   1.137 +                    res = getResources().getIdentifier(resourceName, "xml", getPackageName());
   1.138 +                    if (res == 0) {
   1.139 +                        Log.e(LOGTAG, "No resource found named " + resourceName);
   1.140 +                    }
   1.141 +                }
   1.142 +            }
   1.143 +            if (res == 0) {
   1.144 +                // No resource specified, or the resource was invalid; use the default preferences screen.
   1.145 +                Log.e(LOGTAG, "Displaying default settings.");
   1.146 +                res = R.xml.preferences;
   1.147 +            }
   1.148 +            addPreferencesFromResource(res);
   1.149 +        }
   1.150 +
   1.151 +        registerEventListener("Sanitize:Finished");
   1.152 +
   1.153 +        // Add handling for long-press click.
   1.154 +        // This is only for Android 3.0 and below (which use the long-press-context-menu paradigm).
   1.155 +        final ListView mListView = getListView();
   1.156 +        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
   1.157 +            @Override
   1.158 +            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
   1.159 +                // Call long-click handler if it the item implements it.
   1.160 +                final ListAdapter listAdapter = ((ListView) parent).getAdapter();
   1.161 +                final Object listItem = listAdapter.getItem(position);
   1.162 +
   1.163 +                // Only CustomListPreference handles long clicks.
   1.164 +                if (listItem instanceof CustomListPreference && listItem instanceof View.OnLongClickListener) {
   1.165 +                    final View.OnLongClickListener longClickListener = (View.OnLongClickListener) listItem;
   1.166 +                    return longClickListener.onLongClick(view);
   1.167 +                }
   1.168 +                return false;
   1.169 +            }
   1.170 +        });
   1.171 +
   1.172 +        if (Build.VERSION.SDK_INT >= 14 && getActionBar() != null)
   1.173 +            getActionBar().setHomeButtonEnabled(true);
   1.174 +
   1.175 +        // If launched from notification, explicitly cancel the notification.
   1.176 +        if (intentExtras != null && intentExtras.containsKey(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION)) {
   1.177 +            NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
   1.178 +            notificationManager.cancel(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode());
   1.179 +        }
   1.180 +    }
   1.181 +
   1.182 +    /**
   1.183 +     * Set intent to display top-level settings fragment.
   1.184 +     */
   1.185 +    private void setupTopLevelFragmentIntent() {
   1.186 +        Intent intent = getIntent();
   1.187 +        // Check intent to determine settings screen to display.
   1.188 +        Bundle intentExtras = intent.getExtras();
   1.189 +        Bundle fragmentArgs = new Bundle();
   1.190 +        // Add resource argument to fragment if it exists.
   1.191 +        if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
   1.192 +            String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES);
   1.193 +            fragmentArgs.putString(INTENT_EXTRA_RESOURCES, resourceName);
   1.194 +        } else {
   1.195 +            // Use top-level settings screen.
   1.196 +            if (!onIsMultiPane()) {
   1.197 +                fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences");
   1.198 +            } else {
   1.199 +                fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences_customize_tablet");
   1.200 +            }
   1.201 +        }
   1.202 +
   1.203 +        // Build fragment intent.
   1.204 +        intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
   1.205 +        intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
   1.206 +    }
   1.207 +
   1.208 +    @Override
   1.209 +    public void onBuildHeaders(List<Header> target) {
   1.210 +        if (onIsMultiPane())
   1.211 +            loadHeadersFromResource(R.xml.preference_headers, target);
   1.212 +    }
   1.213 +
   1.214 +    @Override
   1.215 +    public void onWindowFocusChanged(boolean hasFocus) {
   1.216 +        if (!hasFocus || mInitialized)
   1.217 +            return;
   1.218 +
   1.219 +        mInitialized = true;
   1.220 +        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
   1.221 +            PreferenceScreen screen = getPreferenceScreen();
   1.222 +            mPrefsRequestId = setupPreferences(screen);
   1.223 +        }
   1.224 +    }
   1.225 +
   1.226 +    @Override
   1.227 +    protected void onDestroy() {
   1.228 +        super.onDestroy();
   1.229 +        unregisterEventListener("Sanitize:Finished");
   1.230 +        if (mPrefsRequestId > 0) {
   1.231 +            PrefsHelper.removeObserver(mPrefsRequestId);
   1.232 +        }
   1.233 +    }
   1.234 +
   1.235 +    @Override
   1.236 +    public void onPause() {
   1.237 +        super.onPause();
   1.238 +
   1.239 +        if (getApplication() instanceof GeckoApplication) {
   1.240 +            ((GeckoApplication) getApplication()).onActivityPause(this);
   1.241 +        }
   1.242 +    }
   1.243 +
   1.244 +    @Override
   1.245 +    public void onResume() {
   1.246 +        super.onResume();
   1.247 +
   1.248 +        if (getApplication() instanceof GeckoApplication) {
   1.249 +            ((GeckoApplication) getApplication()).onActivityResume(this);
   1.250 +        }
   1.251 +    }
   1.252 +
   1.253 +    @Override
   1.254 +    public void startActivity(Intent intent) {
   1.255 +        // For settings, we want to be able to pass results up the chain
   1.256 +        // of preference screens so Settings can behave as a single unit.
   1.257 +        // Specifically, when we open a link, we want to back out of all
   1.258 +        // the settings screens.
   1.259 +        // We need to start nested PreferenceScreens withStartActivityForResult().
   1.260 +        // Android doesn't let us do that (see Preference.onClick), so we're overriding here.
   1.261 +        startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
   1.262 +    }
   1.263 +
   1.264 +    @Override
   1.265 +    public void startWithFragment(String fragmentName, Bundle args,
   1.266 +            Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
   1.267 +        // Overriding because we want to use startActivityForResult for Fragment intents.
   1.268 +        Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
   1.269 +        if (resultTo == null) {
   1.270 +            startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
   1.271 +        } else {
   1.272 +            resultTo.startActivityForResult(intent, resultRequestCode);
   1.273 +        }
   1.274 +    }
   1.275 +
   1.276 +    @Override
   1.277 +    public void onActivityResult(int requestCode, int resultCode, Intent data) {
   1.278 +        switch (requestCode) {
   1.279 +          case REQUEST_CODE_PREF_SCREEN:
   1.280 +              if (resultCode == RESULT_CODE_EXIT_SETTINGS) {
   1.281 +                  // Pass this result up to the parent activity.
   1.282 +                  setResult(RESULT_CODE_EXIT_SETTINGS);
   1.283 +                  finish();
   1.284 +              }
   1.285 +              break;
   1.286 +
   1.287 +          case HomePanelPicker.REQUEST_CODE_ADD_PANEL:
   1.288 +              switch (resultCode) {
   1.289 +                  case Activity.RESULT_OK:
   1.290 +                     // Panel installed, refresh panels list.
   1.291 +                     mPanelsPreferenceCategory.refresh();
   1.292 +                      break;
   1.293 +                  case Activity.RESULT_CANCELED:
   1.294 +                      // Dialog was cancelled, do nothing.
   1.295 +                      break;
   1.296 +                  default:
   1.297 +                      Log.w(LOGTAG, "Unhandled ADD_PANEL result code " + requestCode);
   1.298 +                      break;
   1.299 +              }
   1.300 +              break;
   1.301 +        }
   1.302 +    }
   1.303 +
   1.304 +    @Override
   1.305 +    public void handleMessage(String event, JSONObject message) {
   1.306 +        try {
   1.307 +            if (event.equals("Sanitize:Finished")) {
   1.308 +                boolean success = message.getBoolean("success");
   1.309 +                final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail;
   1.310 +                final Context context = this;
   1.311 +                ThreadUtils.postToUiThread(new Runnable () {
   1.312 +                    @Override
   1.313 +                    public void run() {
   1.314 +                        Toast.makeText(context, stringRes, Toast.LENGTH_SHORT).show();
   1.315 +                    }
   1.316 +                });
   1.317 +            }
   1.318 +        } catch (Exception e) {
   1.319 +            Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
   1.320 +        }
   1.321 +    }
   1.322 +
   1.323 +    /**
   1.324 +      * Initialize all of the preferences (native of Gecko ones) for this screen.
   1.325 +      *
   1.326 +      * @param prefs The android.preference.PreferenceGroup to initialize
   1.327 +      * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
   1.328 +      *         to monitor changes to Gecko prefs.
   1.329 +      */
   1.330 +    public int setupPreferences(PreferenceGroup prefs) {
   1.331 +        ArrayList<String> list = new ArrayList<String>();
   1.332 +        setupPreferences(prefs, list);
   1.333 +        return getGeckoPreferences(prefs, list);
   1.334 +    }
   1.335 +
   1.336 +    /**
   1.337 +      * Recursively loop through a PreferenceGroup. Initialize native Android prefs,
   1.338 +      * and build a list of Gecko preferences in the passed in prefs array
   1.339 +      *
   1.340 +      * @param preferences The android.preference.PreferenceGroup to initialize
   1.341 +      * @param prefs An ArrayList to fill with Gecko preferences that need to be
   1.342 +      *        initialized
   1.343 +      * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
   1.344 +      *         to monitor changes to Gecko prefs.
   1.345 +      */
   1.346 +    private void setupPreferences(PreferenceGroup preferences, ArrayList<String> prefs) {
   1.347 +        for (int i = 0; i < preferences.getPreferenceCount(); i++) {
   1.348 +            Preference pref = preferences.getPreference(i);
   1.349 +            String key = pref.getKey();
   1.350 +            if (pref instanceof PreferenceGroup) {
   1.351 +                // If no datareporting is enabled, remove UI.
   1.352 +                if (PREFS_DATA_REPORTING_PREFERENCES.equals(key)) {
   1.353 +                    if (!AppConstants.MOZ_DATA_REPORTING) {
   1.354 +                        preferences.removePreference(pref);
   1.355 +                        i--;
   1.356 +                        continue;
   1.357 +                    }
   1.358 +                } else if (pref instanceof PanelsPreferenceCategory) {
   1.359 +                    mPanelsPreferenceCategory = (PanelsPreferenceCategory) pref;
   1.360 +                }
   1.361 +                setupPreferences((PreferenceGroup) pref, prefs);
   1.362 +            } else {
   1.363 +                pref.setOnPreferenceChangeListener(this);
   1.364 +                if (!AppConstants.MOZ_UPDATER &&
   1.365 +                    PREFS_UPDATER_AUTODOWNLOAD.equals(key)) {
   1.366 +                    preferences.removePreference(pref);
   1.367 +                    i--;
   1.368 +                    continue;
   1.369 +                } else if (AppConstants.RELEASE_BUILD &&
   1.370 +                           PREFS_DISPLAY_REFLOW_ON_ZOOM.equals(key)) {
   1.371 +                    // Remove UI for reflow on release builds.
   1.372 +                    preferences.removePreference(pref);
   1.373 +                    i--;
   1.374 +                    continue;
   1.375 +                } else if (!AppConstants.MOZ_TELEMETRY_REPORTING &&
   1.376 +                           PREFS_TELEMETRY_ENABLED.equals(key)) {
   1.377 +                    preferences.removePreference(pref);
   1.378 +                    i--;
   1.379 +                    continue;
   1.380 +                } else if (!AppConstants.MOZ_SERVICES_HEALTHREPORT &&
   1.381 +                           (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(key) ||
   1.382 +                            PREFS_HEALTHREPORT_LINK.equals(key))) {
   1.383 +                    preferences.removePreference(pref);
   1.384 +                    i--;
   1.385 +                    continue;
   1.386 +                } else if (!AppConstants.MOZ_CRASHREPORTER &&
   1.387 +                           PREFS_CRASHREPORTER_ENABLED.equals(key)) {
   1.388 +                    preferences.removePreference(pref);
   1.389 +                    i--;
   1.390 +                    continue;
   1.391 +                } else if (AppConstants.RELEASE_BUILD && PREFS_GEO_REPORTING.equals(key)) {
   1.392 +                    // We don't build wifi/cell tower collection in release builds, so hide the UI.
   1.393 +                    preferences.removePreference(pref);
   1.394 +                    i--;
   1.395 +                    continue;
   1.396 +                } else if (PREFS_DEVTOOLS_REMOTE_ENABLED.equals(key)) {
   1.397 +                    final Context thisContext = this;
   1.398 +                    pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
   1.399 +                        @Override
   1.400 +                        public boolean onPreferenceClick(Preference preference) {
   1.401 +                            // Display toast to remind setting up tcp forwarding.
   1.402 +                            if (((CheckBoxPreference) preference).isChecked()) {
   1.403 +                                Toast.makeText(thisContext, R.string.devtools_remote_debugging_forward, Toast.LENGTH_SHORT).show();
   1.404 +                            }
   1.405 +                            return true;
   1.406 +                        }
   1.407 +                    });
   1.408 +                } else if (PREFS_RESTORE_SESSION.equals(key)) {
   1.409 +                    // Set the summary string to the current entry. The summary
   1.410 +                    // for other list prefs will be set in the PrefsHelper
   1.411 +                    // callback, but since this pref doesn't live in Gecko, we
   1.412 +                    // need to handle it separately.
   1.413 +                    ListPreference listPref = (ListPreference) pref;
   1.414 +                    CharSequence selectedEntry = listPref.getEntry();
   1.415 +                    listPref.setSummary(selectedEntry);
   1.416 +                    continue;
   1.417 +                } else if (PREFS_SYNC.equals(key) && GeckoProfile.get(this).inGuestMode()) {
   1.418 +                    // Don't show sync prefs while in guest mode.
   1.419 +                    preferences.removePreference(pref);
   1.420 +                    i--;
   1.421 +                    continue;
   1.422 +                } else if (PREFS_SEARCH_RESTORE_DEFAULTS.equals(key)) {
   1.423 +                    pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
   1.424 +                        @Override
   1.425 +                        public boolean onPreferenceClick(Preference preference) {
   1.426 +                            GeckoPreferences.this.restoreDefaultSearchEngines();
   1.427 +                            return true;
   1.428 +                        }
   1.429 +                    });
   1.430 +                } else if (PREFS_HOME_ADD_PANEL.equals(key)) {
   1.431 +                    pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
   1.432 +                        @Override
   1.433 +                        public boolean onPreferenceClick(Preference preference) {
   1.434 +                            Intent dialogIntent = new Intent(GeckoPreferences.this, HomePanelPicker.class);
   1.435 +                            startActivityForResult(dialogIntent, HomePanelPicker.REQUEST_CODE_ADD_PANEL);
   1.436 +                            return true;
   1.437 +                        }
   1.438 +                    });
   1.439 +                }
   1.440 +
   1.441 +                // Some Preference UI elements are not actually preferences,
   1.442 +                // but they require a key to work correctly. For example,
   1.443 +                // "Clear private data" requires a key for its state to be
   1.444 +                // saved when the orientation changes. It uses the
   1.445 +                // "android.not_a_preference.privacy.clear" key - which doesn't
   1.446 +                // exist in Gecko - to satisfy this requirement.
   1.447 +                if (key != null && !key.startsWith(NON_PREF_PREFIX)) {
   1.448 +                    prefs.add(key);
   1.449 +                }
   1.450 +            }
   1.451 +        }
   1.452 +    }
   1.453 +
   1.454 +    /**
   1.455 +     * Restore default search engines in Gecko and retrigger a search engine refresh.
   1.456 +     */
   1.457 +    protected void restoreDefaultSearchEngines() {
   1.458 +        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:RestoreDefaults", null));
   1.459 +
   1.460 +        // Send message to Gecko to get engines. SearchPreferenceCategory listens for the response.
   1.461 +        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
   1.462 +    }
   1.463 +
   1.464 +    @Override
   1.465 +    public boolean onOptionsItemSelected(MenuItem item) {
   1.466 +        int itemId = item.getItemId();
   1.467 +        switch (itemId) {
   1.468 +            case android.R.id.home:
   1.469 +                finish();
   1.470 +                return true;
   1.471 +        }
   1.472 +
   1.473 +        // Generated R.id.* apparently aren't constant expressions, so they can't be switched.
   1.474 +        if (itemId == R.id.restore_defaults) {
   1.475 +            restoreDefaultSearchEngines();
   1.476 +            return true;
   1.477 +       }
   1.478 +
   1.479 +        return super.onOptionsItemSelected(item);
   1.480 +    }
   1.481 +
   1.482 +    final private int DIALOG_CREATE_MASTER_PASSWORD = 0;
   1.483 +    final private int DIALOG_REMOVE_MASTER_PASSWORD = 1;
   1.484 +
   1.485 +    public static void setCharEncodingState(boolean enabled) {
   1.486 +        sIsCharEncodingEnabled = enabled;
   1.487 +    }
   1.488 +
   1.489 +    public static boolean getCharEncodingState() {
   1.490 +        return sIsCharEncodingEnabled;
   1.491 +    }
   1.492 +
   1.493 +    public static void broadcastAction(final Context context, final Intent intent) {
   1.494 +        fillIntentWithProfileInfo(context, intent);
   1.495 +        context.sendBroadcast(intent, GlobalConstants.PER_ANDROID_PACKAGE_PERMISSION);
   1.496 +    }
   1.497 +
   1.498 +    /**
   1.499 +     * Broadcast an intent with <code>pref</code>, <code>branch</code>, and
   1.500 +     * <code>enabled</code> extras. This is intended to represent the
   1.501 +     * notification of a preference value to observers.
   1.502 +     *
   1.503 +     * The broadcast will be sent only to receivers registered with the
   1.504 +     * (Fennec-specific) per-Android package permission.
   1.505 +     */
   1.506 +    public static void broadcastPrefAction(final Context context,
   1.507 +                                           final String action,
   1.508 +                                           final String pref,
   1.509 +                                           final boolean value) {
   1.510 +        final Intent intent = new Intent(action)
   1.511 +                .putExtra("pref", pref)
   1.512 +                .putExtra("branch", GeckoSharedPrefs.APP_PREFS_NAME)
   1.513 +                .putExtra("enabled", value);
   1.514 +        broadcastAction(context, intent);
   1.515 +    }
   1.516 +
   1.517 +    private static void fillIntentWithProfileInfo(final Context context, final Intent intent) {
   1.518 +        // There is a race here, but GeckoProfile returns the default profile
   1.519 +        // when Gecko is not explicitly running for a different profile.  In a
   1.520 +        // multi-profile world, this will need to be updated (possibly to
   1.521 +        // broadcast settings for all profiles).  See Bug 882182.
   1.522 +        GeckoProfile profile = GeckoProfile.get(context);
   1.523 +        if (profile != null) {
   1.524 +            intent.putExtra("profileName", profile.getName())
   1.525 +                  .putExtra("profilePath", profile.getDir().getAbsolutePath());
   1.526 +        }
   1.527 +    }
   1.528 +
   1.529 +    /**
   1.530 +     * Broadcast the provided value as the value of the
   1.531 +     * <code>PREFS_ANNOUNCEMENTS_ENABLED</code> pref.
   1.532 +     */
   1.533 +    public static void broadcastAnnouncementsPref(final Context context, final boolean value) {
   1.534 +        broadcastPrefAction(context,
   1.535 +                            AnnouncementsConstants.ACTION_ANNOUNCEMENTS_PREF,
   1.536 +                            PREFS_ANNOUNCEMENTS_ENABLED,
   1.537 +                            value);
   1.538 +    }
   1.539 +
   1.540 +    /**
   1.541 +     * Broadcast the current value of the
   1.542 +     * <code>PREFS_ANNOUNCEMENTS_ENABLED</code> pref.
   1.543 +     */
   1.544 +    public static void broadcastAnnouncementsPref(final Context context) {
   1.545 +        final boolean value = getBooleanPref(context, PREFS_ANNOUNCEMENTS_ENABLED, true);
   1.546 +        broadcastAnnouncementsPref(context, value);
   1.547 +    }
   1.548 +
   1.549 +    /**
   1.550 +     * Broadcast the provided value as the value of the
   1.551 +     * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
   1.552 +     */
   1.553 +    public static void broadcastHealthReportUploadPref(final Context context, final boolean value) {
   1.554 +        broadcastPrefAction(context,
   1.555 +                            HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF,
   1.556 +                            PREFS_HEALTHREPORT_UPLOAD_ENABLED,
   1.557 +                            value);
   1.558 +    }
   1.559 +
   1.560 +    /**
   1.561 +     * Broadcast the current value of the
   1.562 +     * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
   1.563 +     */
   1.564 +    public static void broadcastHealthReportUploadPref(final Context context) {
   1.565 +        final boolean value = getBooleanPref(context, PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
   1.566 +        broadcastHealthReportUploadPref(context, value);
   1.567 +    }
   1.568 +
   1.569 +    public static void broadcastHealthReportPrune(final Context context) {
   1.570 +        final Intent intent = new Intent(HealthReportConstants.ACTION_HEALTHREPORT_PRUNE);
   1.571 +        broadcastAction(context, intent);
   1.572 +    }
   1.573 +
   1.574 +    /**
   1.575 +     * Return the value of the named preference in the default preferences file.
   1.576 +     *
   1.577 +     * This corresponds to the storage that backs preferences.xml.
   1.578 +     * @param context a <code>Context</code>; the
   1.579 +     *                <code>PreferenceActivity</code> will suffice, but this
   1.580 +     *                method is intended to be called from other contexts
   1.581 +     *                within the application, not just this <code>Activity</code>.
   1.582 +     * @param name    the name of the preference to retrieve.
   1.583 +     * @param def     the default value to return if the preference is not present.
   1.584 +     * @return        the value of the preference, or the default.
   1.585 +     */
   1.586 +    public static boolean getBooleanPref(final Context context, final String name, boolean def) {
   1.587 +        final SharedPreferences prefs = GeckoSharedPrefs.forApp(context);
   1.588 +        return prefs.getBoolean(name, def);
   1.589 +    }
   1.590 +
   1.591 +    @Override
   1.592 +    public boolean onPreferenceChange(Preference preference, Object newValue) {
   1.593 +        String prefName = preference.getKey();
   1.594 +        if (PREFS_MP_ENABLED.equals(prefName)) {
   1.595 +            showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
   1.596 +
   1.597 +            // We don't want the "use master password" pref to change until the
   1.598 +            // user has gone through the dialog.
   1.599 +            return false;
   1.600 +        } else if (PREFS_MENU_CHAR_ENCODING.equals(prefName)) {
   1.601 +            setCharEncodingState(((String) newValue).equals("true"));
   1.602 +        } else if (PREFS_ANNOUNCEMENTS_ENABLED.equals(prefName)) {
   1.603 +            // Send a broadcast intent to the product announcements service, either to start or
   1.604 +            // to stop the repeated background checks.
   1.605 +            broadcastAnnouncementsPref(this, ((Boolean) newValue).booleanValue());
   1.606 +        } else if (PREFS_UPDATER_AUTODOWNLOAD.equals(prefName)) {
   1.607 +            org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(this, (String) newValue);
   1.608 +        } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(prefName)) {
   1.609 +            // The healthreport pref only lives in Android, so we do not persist
   1.610 +            // to Gecko, but we do broadcast intent to the health report
   1.611 +            // background uploader service, which will start or stop the
   1.612 +            // repeated background upload attempts.
   1.613 +            broadcastHealthReportUploadPref(this, ((Boolean) newValue).booleanValue());
   1.614 +        } else if (PREFS_GEO_REPORTING.equals(prefName)) {
   1.615 +            // Translate boolean value to int for geo reporting pref.
   1.616 +            newValue = ((Boolean) newValue) ? 1 : 0;
   1.617 +        }
   1.618 +
   1.619 +        // Send Gecko-side pref changes to Gecko
   1.620 +        if (!TextUtils.isEmpty(prefName) && !prefName.startsWith(NON_PREF_PREFIX)) {
   1.621 +            PrefsHelper.setPref(prefName, newValue);
   1.622 +        }
   1.623 +
   1.624 +        if (preference instanceof ListPreference) {
   1.625 +            // We need to find the entry for the new value
   1.626 +            int newIndex = ((ListPreference) preference).findIndexOfValue((String) newValue);
   1.627 +            CharSequence newEntry = ((ListPreference) preference).getEntries()[newIndex];
   1.628 +            ((ListPreference) preference).setSummary(newEntry);
   1.629 +        } else if (preference instanceof LinkPreference) {
   1.630 +            setResult(RESULT_CODE_EXIT_SETTINGS);
   1.631 +            finish();
   1.632 +        } else if (preference instanceof FontSizePreference) {
   1.633 +            final FontSizePreference fontSizePref = (FontSizePreference) preference;
   1.634 +            fontSizePref.setSummary(fontSizePref.getSavedFontSizeName());
   1.635 +        }
   1.636 +
   1.637 +        return true;
   1.638 +    }
   1.639 +
   1.640 +    private EditText getTextBox(int aHintText) {
   1.641 +        EditText input = new EditText(this);
   1.642 +        int inputtype = InputType.TYPE_CLASS_TEXT;
   1.643 +        inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
   1.644 +        input.setInputType(inputtype);
   1.645 +
   1.646 +        input.setHint(aHintText);
   1.647 +        return input;
   1.648 +    }
   1.649 +
   1.650 +    private class PasswordTextWatcher implements TextWatcher {
   1.651 +        EditText input1 = null;
   1.652 +        EditText input2 = null;
   1.653 +        AlertDialog dialog = null;
   1.654 +
   1.655 +        PasswordTextWatcher(EditText aInput1, EditText aInput2, AlertDialog aDialog) {
   1.656 +            input1 = aInput1;
   1.657 +            input2 = aInput2;
   1.658 +            dialog = aDialog;
   1.659 +        }
   1.660 +
   1.661 +        @Override
   1.662 +        public void afterTextChanged(Editable s) {
   1.663 +            if (dialog == null)
   1.664 +                return;
   1.665 +
   1.666 +            String text1 = input1.getText().toString();
   1.667 +            String text2 = input2.getText().toString();
   1.668 +            boolean disabled = TextUtils.isEmpty(text1) || TextUtils.isEmpty(text2) || !text1.equals(text2);
   1.669 +            dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
   1.670 +        }
   1.671 +
   1.672 +        @Override
   1.673 +        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
   1.674 +        @Override
   1.675 +        public void onTextChanged(CharSequence s, int start, int before, int count) { }
   1.676 +    }
   1.677 +
   1.678 +    private class EmptyTextWatcher implements TextWatcher {
   1.679 +        EditText input = null;
   1.680 +        AlertDialog dialog = null;
   1.681 +
   1.682 +        EmptyTextWatcher(EditText aInput, AlertDialog aDialog) {
   1.683 +            input = aInput;
   1.684 +            dialog = aDialog;
   1.685 +        }
   1.686 +
   1.687 +        @Override
   1.688 +        public void afterTextChanged(Editable s) {
   1.689 +            if (dialog == null)
   1.690 +                return;
   1.691 +
   1.692 +            String text = input.getText().toString();
   1.693 +            boolean disabled = TextUtils.isEmpty(text);
   1.694 +            dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
   1.695 +        }
   1.696 +
   1.697 +        @Override
   1.698 +        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
   1.699 +        @Override
   1.700 +        public void onTextChanged(CharSequence s, int start, int before, int count) { }
   1.701 +    }
   1.702 +
   1.703 +    @Override
   1.704 +    protected Dialog onCreateDialog(int id) {
   1.705 +        AlertDialog.Builder builder = new AlertDialog.Builder(this);
   1.706 +        LinearLayout linearLayout = new LinearLayout(this);
   1.707 +        linearLayout.setOrientation(LinearLayout.VERTICAL);
   1.708 +        AlertDialog dialog = null;
   1.709 +        switch(id) {
   1.710 +            case DIALOG_CREATE_MASTER_PASSWORD:
   1.711 +                final EditText input1 = getTextBox(R.string.masterpassword_password);
   1.712 +                final EditText input2 = getTextBox(R.string.masterpassword_confirm);
   1.713 +                linearLayout.addView(input1);
   1.714 +                linearLayout.addView(input2);
   1.715 +
   1.716 +                builder.setTitle(R.string.masterpassword_create_title)
   1.717 +                       .setView((View) linearLayout)
   1.718 +                       .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {  
   1.719 +                            @Override
   1.720 +                            public void onClick(DialogInterface dialog, int which) {
   1.721 +                                JSONObject jsonPref = new JSONObject();
   1.722 +                                try {
   1.723 +                                    jsonPref.put("name", PREFS_MP_ENABLED);
   1.724 +                                    jsonPref.put("type", "string");
   1.725 +                                    jsonPref.put("value", input1.getText().toString());
   1.726 +                    
   1.727 +                                    GeckoEvent event = GeckoEvent.createBroadcastEvent("Preferences:Set", jsonPref.toString());
   1.728 +                                    GeckoAppShell.sendEventToGecko(event);
   1.729 +                                } catch(Exception ex) {
   1.730 +                                    Log.e(LOGTAG, "Error setting master password", ex);
   1.731 +                                }
   1.732 +                                return;
   1.733 +                            }
   1.734 +                        })
   1.735 +                        .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {  
   1.736 +                            @Override
   1.737 +                            public void onClick(DialogInterface dialog, int which) {
   1.738 +                                return;
   1.739 +                            }
   1.740 +                        });
   1.741 +                        dialog = builder.create();
   1.742 +                        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
   1.743 +                            @Override
   1.744 +                            public void onShow(DialogInterface dialog) {
   1.745 +                                input1.setText("");
   1.746 +                                input2.setText("");
   1.747 +                                input1.requestFocus();
   1.748 +                            }
   1.749 +                        });
   1.750 +
   1.751 +                        PasswordTextWatcher watcher = new PasswordTextWatcher(input1, input2, dialog);
   1.752 +                        input1.addTextChangedListener((TextWatcher) watcher);
   1.753 +                        input2.addTextChangedListener((TextWatcher) watcher);
   1.754 +
   1.755 +                break;
   1.756 +            case DIALOG_REMOVE_MASTER_PASSWORD:
   1.757 +                final EditText input = getTextBox(R.string.masterpassword_password);
   1.758 +                linearLayout.addView(input);
   1.759 +
   1.760 +                builder.setTitle(R.string.masterpassword_remove_title)
   1.761 +                       .setView((View) linearLayout)
   1.762 +                       .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {  
   1.763 +                            @Override
   1.764 +                            public void onClick(DialogInterface dialog, int which) {
   1.765 +                                PrefsHelper.setPref(PREFS_MP_ENABLED, input.getText().toString());
   1.766 +                            }
   1.767 +                        })
   1.768 +                        .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {  
   1.769 +                            @Override
   1.770 +                            public void onClick(DialogInterface dialog, int which) {
   1.771 +                                return;
   1.772 +                            }
   1.773 +                        });
   1.774 +                        dialog = builder.create();
   1.775 +                        dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
   1.776 +                            @Override
   1.777 +                            public void onDismiss(DialogInterface dialog) {
   1.778 +                                input.setText("");
   1.779 +                            }
   1.780 +                        });
   1.781 +                        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
   1.782 +                            @Override
   1.783 +                            public void onShow(DialogInterface dialog) {
   1.784 +                                input.setText("");
   1.785 +                            }
   1.786 +                        });
   1.787 +                        input.addTextChangedListener(new EmptyTextWatcher(input, dialog));
   1.788 +                break;
   1.789 +            default:
   1.790 +                return null;
   1.791 +        }
   1.792 +
   1.793 +        return dialog;
   1.794 +    }
   1.795 +
   1.796 +    // Initialize preferences by requesting the preference values from Gecko
   1.797 +    private int getGeckoPreferences(final PreferenceGroup screen, ArrayList<String> prefs) {
   1.798 +        return PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
   1.799 +            private Preference getField(String prefName) {
   1.800 +                return screen.findPreference(prefName);
   1.801 +            }
   1.802 +
   1.803 +            // Handle v14 TwoStatePreference with backwards compatibility.
   1.804 +            class CheckBoxPrefSetter {
   1.805 +                public void setBooleanPref(Preference preference, boolean value) {
   1.806 +                    if ((preference instanceof CheckBoxPreference) &&
   1.807 +                       ((CheckBoxPreference) preference).isChecked() != value) {
   1.808 +                        ((CheckBoxPreference) preference).setChecked(value);
   1.809 +                    }
   1.810 +                }
   1.811 +            }
   1.812 +
   1.813 +            class TwoStatePrefSetter extends CheckBoxPrefSetter {
   1.814 +                @Override
   1.815 +                public void setBooleanPref(Preference preference, boolean value) {
   1.816 +                    if ((preference instanceof TwoStatePreference) &&
   1.817 +                       ((TwoStatePreference) preference).isChecked() != value) {
   1.818 +                        ((TwoStatePreference) preference).setChecked(value);
   1.819 +                    }
   1.820 +                }
   1.821 +            }
   1.822 +
   1.823 +            @Override
   1.824 +            public void prefValue(String prefName, final boolean value) {
   1.825 +                final Preference pref = getField(prefName);
   1.826 +                final CheckBoxPrefSetter prefSetter;
   1.827 +                if (Build.VERSION.SDK_INT < 14) {
   1.828 +                    prefSetter = new CheckBoxPrefSetter();
   1.829 +                } else {
   1.830 +                    prefSetter = new TwoStatePrefSetter();
   1.831 +                }
   1.832 +                ThreadUtils.postToUiThread(new Runnable() {
   1.833 +                    public void run() {
   1.834 +                        prefSetter.setBooleanPref(pref, value);
   1.835 +                    }
   1.836 +                });
   1.837 +            }
   1.838 +
   1.839 +            @Override
   1.840 +            public void prefValue(String prefName, final String value) {
   1.841 +                final Preference pref = getField(prefName);
   1.842 +                if (pref instanceof EditTextPreference) {
   1.843 +                    ThreadUtils.postToUiThread(new Runnable() {
   1.844 +                        @Override
   1.845 +                        public void run() {
   1.846 +                            ((EditTextPreference) pref).setText(value);
   1.847 +                        }
   1.848 +                    });
   1.849 +                } else if (pref instanceof ListPreference) {
   1.850 +                    ThreadUtils.postToUiThread(new Runnable() {
   1.851 +                        @Override
   1.852 +                        public void run() {
   1.853 +                            ((ListPreference) pref).setValue(value);
   1.854 +                            // Set the summary string to the current entry
   1.855 +                            CharSequence selectedEntry = ((ListPreference) pref).getEntry();
   1.856 +                            ((ListPreference) pref).setSummary(selectedEntry);
   1.857 +                        }
   1.858 +                    });
   1.859 +                } else if (pref instanceof FontSizePreference) {
   1.860 +                    final FontSizePreference fontSizePref = (FontSizePreference) pref;
   1.861 +                    fontSizePref.setSavedFontSize(value);
   1.862 +                    final String fontSizeName = fontSizePref.getSavedFontSizeName();
   1.863 +                    ThreadUtils.postToUiThread(new Runnable() {
   1.864 +                        @Override
   1.865 +                        public void run() {
   1.866 +                            fontSizePref.setSummary(fontSizeName); // Ex: "Small".
   1.867 +                        }
   1.868 +                    });
   1.869 +                }
   1.870 +            }
   1.871 +
   1.872 +            @Override
   1.873 +            public void prefValue(String prefName, final int value) {
   1.874 +                final Preference pref = getField(prefName);
   1.875 +                final CheckBoxPrefSetter prefSetter;
   1.876 +                if (PREFS_GEO_REPORTING.equals(prefName)) {
   1.877 +                    if (Build.VERSION.SDK_INT < 14) {
   1.878 +                        prefSetter = new CheckBoxPrefSetter();
   1.879 +                    } else {
   1.880 +                        prefSetter = new TwoStatePrefSetter();
   1.881 +                    }
   1.882 +                    ThreadUtils.postToUiThread(new Runnable() {
   1.883 +                        @Override
   1.884 +                        public void run() {
   1.885 +                            prefSetter.setBooleanPref(pref, value == 1);
   1.886 +                        }
   1.887 +                    });
   1.888 +                } else {
   1.889 +                    Log.w(LOGTAG, "Unhandled int value for pref [" + pref + "]");
   1.890 +                }
   1.891 +            }
   1.892 +
   1.893 +            @Override
   1.894 +            public boolean isObserver() {
   1.895 +                return true;
   1.896 +            }
   1.897 +
   1.898 +            @Override
   1.899 +            public void finish() {
   1.900 +                // enable all preferences once we have them from gecko
   1.901 +                ThreadUtils.postToUiThread(new Runnable() {
   1.902 +                    @Override
   1.903 +                    public void run() {
   1.904 +                        screen.setEnabled(true);
   1.905 +                    }
   1.906 +                });
   1.907 +            }
   1.908 +        });
   1.909 +    }
   1.910 +
   1.911 +    private void registerEventListener(String event) {
   1.912 +        GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
   1.913 +    }
   1.914 +
   1.915 +    private void unregisterEventListener(String event) {
   1.916 +        GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
   1.917 +    }
   1.918 +
   1.919 +    @Override
   1.920 +    public boolean isGeckoActivityOpened() {
   1.921 +        return false;
   1.922 +    }
   1.923 +
   1.924 +    /**
   1.925 +     * Given an Intent instance, add extras to specify which settings section to
   1.926 +     * open.
   1.927 +     *
   1.928 +     * resource should be a valid Android XML resource identifier.
   1.929 +     *
   1.930 +     * The mechanism to open a section differs based on Android version.
   1.931 +     */
   1.932 +    public static void setResourceToOpen(final Intent intent, final String resource) {
   1.933 +        if (intent == null) {
   1.934 +            throw new IllegalArgumentException("intent must not be null");
   1.935 +        }
   1.936 +        if (resource == null) {
   1.937 +            return;
   1.938 +        }
   1.939 +
   1.940 +        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
   1.941 +            intent.putExtra("resource", resource);
   1.942 +        } else {
   1.943 +            intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
   1.944 +
   1.945 +            Bundle fragmentArgs = new Bundle();
   1.946 +            fragmentArgs.putString("resource", resource);
   1.947 +            intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
   1.948 +        }
   1.949 +    }
   1.950 +}

mercurial