mobile/android/base/preferences/GeckoPreferences.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.preferences;
michael@0 7
michael@0 8 import java.util.ArrayList;
michael@0 9 import java.util.List;
michael@0 10
michael@0 11 import org.json.JSONObject;
michael@0 12 import org.mozilla.gecko.AppConstants;
michael@0 13 import org.mozilla.gecko.DataReportingNotification;
michael@0 14 import org.mozilla.gecko.GeckoActivityStatus;
michael@0 15 import org.mozilla.gecko.GeckoApp;
michael@0 16 import org.mozilla.gecko.GeckoAppShell;
michael@0 17 import org.mozilla.gecko.GeckoApplication;
michael@0 18 import org.mozilla.gecko.GeckoEvent;
michael@0 19 import org.mozilla.gecko.GeckoProfile;
michael@0 20 import org.mozilla.gecko.GeckoSharedPrefs;
michael@0 21 import org.mozilla.gecko.PrefsHelper;
michael@0 22 import org.mozilla.gecko.R;
michael@0 23 import org.mozilla.gecko.background.announcements.AnnouncementsConstants;
michael@0 24 import org.mozilla.gecko.background.common.GlobalConstants;
michael@0 25 import org.mozilla.gecko.background.healthreport.HealthReportConstants;
michael@0 26 import org.mozilla.gecko.home.HomePanelPicker;
michael@0 27 import org.mozilla.gecko.util.GeckoEventListener;
michael@0 28 import org.mozilla.gecko.util.ThreadUtils;
michael@0 29
michael@0 30 import android.app.Activity;
michael@0 31 import android.app.AlertDialog;
michael@0 32 import android.app.Dialog;
michael@0 33 import android.app.Fragment;
michael@0 34 import android.app.NotificationManager;
michael@0 35 import android.content.Context;
michael@0 36 import android.content.DialogInterface;
michael@0 37 import android.content.Intent;
michael@0 38 import android.content.SharedPreferences;
michael@0 39 import android.os.Build;
michael@0 40 import android.os.Bundle;
michael@0 41 import android.preference.CheckBoxPreference;
michael@0 42 import android.preference.EditTextPreference;
michael@0 43 import android.preference.ListPreference;
michael@0 44 import android.preference.Preference;
michael@0 45 import android.preference.Preference.OnPreferenceChangeListener;
michael@0 46 import android.preference.Preference.OnPreferenceClickListener;
michael@0 47 import android.preference.PreferenceActivity;
michael@0 48 import android.preference.PreferenceGroup;
michael@0 49 import android.preference.PreferenceScreen;
michael@0 50 import android.preference.TwoStatePreference;
michael@0 51 import android.text.Editable;
michael@0 52 import android.text.InputType;
michael@0 53 import android.text.TextUtils;
michael@0 54 import android.text.TextWatcher;
michael@0 55 import android.util.Log;
michael@0 56 import android.view.MenuItem;
michael@0 57 import android.view.View;
michael@0 58 import android.widget.AdapterView;
michael@0 59 import android.widget.EditText;
michael@0 60 import android.widget.LinearLayout;
michael@0 61 import android.widget.ListAdapter;
michael@0 62 import android.widget.ListView;
michael@0 63 import android.widget.Toast;
michael@0 64
michael@0 65 public class GeckoPreferences
michael@0 66 extends PreferenceActivity
michael@0 67 implements OnPreferenceChangeListener, GeckoEventListener, GeckoActivityStatus
michael@0 68 {
michael@0 69 private static final String LOGTAG = "GeckoPreferences";
michael@0 70
michael@0 71 private static final String NON_PREF_PREFIX = "android.not_a_preference.";
michael@0 72 public static final String INTENT_EXTRA_RESOURCES = "resource";
michael@0 73 public static String PREFS_HEALTHREPORT_UPLOAD_ENABLED = NON_PREF_PREFIX + "healthreport.uploadEnabled";
michael@0 74
michael@0 75 private static boolean sIsCharEncodingEnabled = false;
michael@0 76 private boolean mInitialized = false;
michael@0 77 private int mPrefsRequestId = 0;
michael@0 78 private PanelsPreferenceCategory mPanelsPreferenceCategory;
michael@0 79
michael@0 80 // These match keys in resources/xml*/preferences*.xml
michael@0 81 private static final String PREFS_SEARCH_RESTORE_DEFAULTS = NON_PREF_PREFIX + "search.restore_defaults";
michael@0 82 private static final String PREFS_HOME_ADD_PANEL = NON_PREF_PREFIX + "home.add_panel";
michael@0 83 private static final String PREFS_ANNOUNCEMENTS_ENABLED = NON_PREF_PREFIX + "privacy.announcements.enabled";
michael@0 84 private static final String PREFS_DATA_REPORTING_PREFERENCES = NON_PREF_PREFIX + "datareporting.preferences";
michael@0 85 private static final String PREFS_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
michael@0 86 private static final String PREFS_CRASHREPORTER_ENABLED = "datareporting.crashreporter.submitEnabled";
michael@0 87 private static final String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
michael@0 88 private static final String PREFS_MP_ENABLED = "privacy.masterpassword.enabled";
michael@0 89 private static final String PREFS_UPDATER_AUTODOWNLOAD = "app.update.autodownload";
michael@0 90 private static final String PREFS_GEO_REPORTING = "app.geo.reportdata";
michael@0 91 private static final String PREFS_GEO_LEARN_MORE = NON_PREF_PREFIX + "geo.learn_more";
michael@0 92 private static final String PREFS_HEALTHREPORT_LINK = NON_PREF_PREFIX + "healthreport.link";
michael@0 93 private static final String PREFS_DEVTOOLS_REMOTE_ENABLED = "devtools.debugger.remote-enabled";
michael@0 94 private static final String PREFS_DISPLAY_REFLOW_ON_ZOOM = "browser.zoom.reflowOnZoom";
michael@0 95 private static final String PREFS_SYNC = NON_PREF_PREFIX + "sync";
michael@0 96
michael@0 97 public static final String PREFS_RESTORE_SESSION = NON_PREF_PREFIX + "restoreSession3";
michael@0 98
michael@0 99 // These values are chosen to be distinct from other Activity constants.
michael@0 100 private static final int REQUEST_CODE_PREF_SCREEN = 5;
michael@0 101 private static final int RESULT_CODE_EXIT_SETTINGS = 6;
michael@0 102
michael@0 103 @Override
michael@0 104 protected void onCreate(Bundle savedInstanceState) {
michael@0 105
michael@0 106 // For Android v11+ where we use Fragments (v11+ only due to bug 866352),
michael@0 107 // check that PreferenceActivity.EXTRA_SHOW_FRAGMENT has been set
michael@0 108 // (or set it) before super.onCreate() is called so Android can display
michael@0 109 // the correct Fragment resource.
michael@0 110
michael@0 111 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
michael@0 112 !getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
michael@0 113 // Set up the default fragment if there is no explicit fragment to show.
michael@0 114 setupTopLevelFragmentIntent();
michael@0 115 }
michael@0 116
michael@0 117 super.onCreate(savedInstanceState);
michael@0 118
michael@0 119 // Use setResourceToOpen to specify these extras.
michael@0 120 Bundle intentExtras = getIntent().getExtras();
michael@0 121
michael@0 122 // For versions of Android lower than Honeycomb, use xml resources instead of
michael@0 123 // Fragments because of an Android bug in ActionBar (described in bug 866352 and
michael@0 124 // fixed in bug 833625).
michael@0 125 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
michael@0 126 // Write prefs to our custom GeckoSharedPrefs file.
michael@0 127 getPreferenceManager().setSharedPreferencesName(GeckoSharedPrefs.APP_PREFS_NAME);
michael@0 128
michael@0 129 int res = 0;
michael@0 130 if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
michael@0 131 // Fetch resource id from intent.
michael@0 132 String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES);
michael@0 133 if (resourceName != null) {
michael@0 134 res = getResources().getIdentifier(resourceName, "xml", getPackageName());
michael@0 135 if (res == 0) {
michael@0 136 Log.e(LOGTAG, "No resource found named " + resourceName);
michael@0 137 }
michael@0 138 }
michael@0 139 }
michael@0 140 if (res == 0) {
michael@0 141 // No resource specified, or the resource was invalid; use the default preferences screen.
michael@0 142 Log.e(LOGTAG, "Displaying default settings.");
michael@0 143 res = R.xml.preferences;
michael@0 144 }
michael@0 145 addPreferencesFromResource(res);
michael@0 146 }
michael@0 147
michael@0 148 registerEventListener("Sanitize:Finished");
michael@0 149
michael@0 150 // Add handling for long-press click.
michael@0 151 // This is only for Android 3.0 and below (which use the long-press-context-menu paradigm).
michael@0 152 final ListView mListView = getListView();
michael@0 153 mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
michael@0 154 @Override
michael@0 155 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
michael@0 156 // Call long-click handler if it the item implements it.
michael@0 157 final ListAdapter listAdapter = ((ListView) parent).getAdapter();
michael@0 158 final Object listItem = listAdapter.getItem(position);
michael@0 159
michael@0 160 // Only CustomListPreference handles long clicks.
michael@0 161 if (listItem instanceof CustomListPreference && listItem instanceof View.OnLongClickListener) {
michael@0 162 final View.OnLongClickListener longClickListener = (View.OnLongClickListener) listItem;
michael@0 163 return longClickListener.onLongClick(view);
michael@0 164 }
michael@0 165 return false;
michael@0 166 }
michael@0 167 });
michael@0 168
michael@0 169 if (Build.VERSION.SDK_INT >= 14 && getActionBar() != null)
michael@0 170 getActionBar().setHomeButtonEnabled(true);
michael@0 171
michael@0 172 // If launched from notification, explicitly cancel the notification.
michael@0 173 if (intentExtras != null && intentExtras.containsKey(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION)) {
michael@0 174 NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
michael@0 175 notificationManager.cancel(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode());
michael@0 176 }
michael@0 177 }
michael@0 178
michael@0 179 /**
michael@0 180 * Set intent to display top-level settings fragment.
michael@0 181 */
michael@0 182 private void setupTopLevelFragmentIntent() {
michael@0 183 Intent intent = getIntent();
michael@0 184 // Check intent to determine settings screen to display.
michael@0 185 Bundle intentExtras = intent.getExtras();
michael@0 186 Bundle fragmentArgs = new Bundle();
michael@0 187 // Add resource argument to fragment if it exists.
michael@0 188 if (intentExtras != null && intentExtras.containsKey(INTENT_EXTRA_RESOURCES)) {
michael@0 189 String resourceName = intentExtras.getString(INTENT_EXTRA_RESOURCES);
michael@0 190 fragmentArgs.putString(INTENT_EXTRA_RESOURCES, resourceName);
michael@0 191 } else {
michael@0 192 // Use top-level settings screen.
michael@0 193 if (!onIsMultiPane()) {
michael@0 194 fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences");
michael@0 195 } else {
michael@0 196 fragmentArgs.putString(INTENT_EXTRA_RESOURCES, "preferences_customize_tablet");
michael@0 197 }
michael@0 198 }
michael@0 199
michael@0 200 // Build fragment intent.
michael@0 201 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
michael@0 202 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
michael@0 203 }
michael@0 204
michael@0 205 @Override
michael@0 206 public void onBuildHeaders(List<Header> target) {
michael@0 207 if (onIsMultiPane())
michael@0 208 loadHeadersFromResource(R.xml.preference_headers, target);
michael@0 209 }
michael@0 210
michael@0 211 @Override
michael@0 212 public void onWindowFocusChanged(boolean hasFocus) {
michael@0 213 if (!hasFocus || mInitialized)
michael@0 214 return;
michael@0 215
michael@0 216 mInitialized = true;
michael@0 217 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
michael@0 218 PreferenceScreen screen = getPreferenceScreen();
michael@0 219 mPrefsRequestId = setupPreferences(screen);
michael@0 220 }
michael@0 221 }
michael@0 222
michael@0 223 @Override
michael@0 224 protected void onDestroy() {
michael@0 225 super.onDestroy();
michael@0 226 unregisterEventListener("Sanitize:Finished");
michael@0 227 if (mPrefsRequestId > 0) {
michael@0 228 PrefsHelper.removeObserver(mPrefsRequestId);
michael@0 229 }
michael@0 230 }
michael@0 231
michael@0 232 @Override
michael@0 233 public void onPause() {
michael@0 234 super.onPause();
michael@0 235
michael@0 236 if (getApplication() instanceof GeckoApplication) {
michael@0 237 ((GeckoApplication) getApplication()).onActivityPause(this);
michael@0 238 }
michael@0 239 }
michael@0 240
michael@0 241 @Override
michael@0 242 public void onResume() {
michael@0 243 super.onResume();
michael@0 244
michael@0 245 if (getApplication() instanceof GeckoApplication) {
michael@0 246 ((GeckoApplication) getApplication()).onActivityResume(this);
michael@0 247 }
michael@0 248 }
michael@0 249
michael@0 250 @Override
michael@0 251 public void startActivity(Intent intent) {
michael@0 252 // For settings, we want to be able to pass results up the chain
michael@0 253 // of preference screens so Settings can behave as a single unit.
michael@0 254 // Specifically, when we open a link, we want to back out of all
michael@0 255 // the settings screens.
michael@0 256 // We need to start nested PreferenceScreens withStartActivityForResult().
michael@0 257 // Android doesn't let us do that (see Preference.onClick), so we're overriding here.
michael@0 258 startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
michael@0 259 }
michael@0 260
michael@0 261 @Override
michael@0 262 public void startWithFragment(String fragmentName, Bundle args,
michael@0 263 Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
michael@0 264 // Overriding because we want to use startActivityForResult for Fragment intents.
michael@0 265 Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
michael@0 266 if (resultTo == null) {
michael@0 267 startActivityForResult(intent, REQUEST_CODE_PREF_SCREEN);
michael@0 268 } else {
michael@0 269 resultTo.startActivityForResult(intent, resultRequestCode);
michael@0 270 }
michael@0 271 }
michael@0 272
michael@0 273 @Override
michael@0 274 public void onActivityResult(int requestCode, int resultCode, Intent data) {
michael@0 275 switch (requestCode) {
michael@0 276 case REQUEST_CODE_PREF_SCREEN:
michael@0 277 if (resultCode == RESULT_CODE_EXIT_SETTINGS) {
michael@0 278 // Pass this result up to the parent activity.
michael@0 279 setResult(RESULT_CODE_EXIT_SETTINGS);
michael@0 280 finish();
michael@0 281 }
michael@0 282 break;
michael@0 283
michael@0 284 case HomePanelPicker.REQUEST_CODE_ADD_PANEL:
michael@0 285 switch (resultCode) {
michael@0 286 case Activity.RESULT_OK:
michael@0 287 // Panel installed, refresh panels list.
michael@0 288 mPanelsPreferenceCategory.refresh();
michael@0 289 break;
michael@0 290 case Activity.RESULT_CANCELED:
michael@0 291 // Dialog was cancelled, do nothing.
michael@0 292 break;
michael@0 293 default:
michael@0 294 Log.w(LOGTAG, "Unhandled ADD_PANEL result code " + requestCode);
michael@0 295 break;
michael@0 296 }
michael@0 297 break;
michael@0 298 }
michael@0 299 }
michael@0 300
michael@0 301 @Override
michael@0 302 public void handleMessage(String event, JSONObject message) {
michael@0 303 try {
michael@0 304 if (event.equals("Sanitize:Finished")) {
michael@0 305 boolean success = message.getBoolean("success");
michael@0 306 final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail;
michael@0 307 final Context context = this;
michael@0 308 ThreadUtils.postToUiThread(new Runnable () {
michael@0 309 @Override
michael@0 310 public void run() {
michael@0 311 Toast.makeText(context, stringRes, Toast.LENGTH_SHORT).show();
michael@0 312 }
michael@0 313 });
michael@0 314 }
michael@0 315 } catch (Exception e) {
michael@0 316 Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
michael@0 317 }
michael@0 318 }
michael@0 319
michael@0 320 /**
michael@0 321 * Initialize all of the preferences (native of Gecko ones) for this screen.
michael@0 322 *
michael@0 323 * @param prefs The android.preference.PreferenceGroup to initialize
michael@0 324 * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
michael@0 325 * to monitor changes to Gecko prefs.
michael@0 326 */
michael@0 327 public int setupPreferences(PreferenceGroup prefs) {
michael@0 328 ArrayList<String> list = new ArrayList<String>();
michael@0 329 setupPreferences(prefs, list);
michael@0 330 return getGeckoPreferences(prefs, list);
michael@0 331 }
michael@0 332
michael@0 333 /**
michael@0 334 * Recursively loop through a PreferenceGroup. Initialize native Android prefs,
michael@0 335 * and build a list of Gecko preferences in the passed in prefs array
michael@0 336 *
michael@0 337 * @param preferences The android.preference.PreferenceGroup to initialize
michael@0 338 * @param prefs An ArrayList to fill with Gecko preferences that need to be
michael@0 339 * initialized
michael@0 340 * @return The integer id for the PrefsHelper.PrefHandlerBase listener added
michael@0 341 * to monitor changes to Gecko prefs.
michael@0 342 */
michael@0 343 private void setupPreferences(PreferenceGroup preferences, ArrayList<String> prefs) {
michael@0 344 for (int i = 0; i < preferences.getPreferenceCount(); i++) {
michael@0 345 Preference pref = preferences.getPreference(i);
michael@0 346 String key = pref.getKey();
michael@0 347 if (pref instanceof PreferenceGroup) {
michael@0 348 // If no datareporting is enabled, remove UI.
michael@0 349 if (PREFS_DATA_REPORTING_PREFERENCES.equals(key)) {
michael@0 350 if (!AppConstants.MOZ_DATA_REPORTING) {
michael@0 351 preferences.removePreference(pref);
michael@0 352 i--;
michael@0 353 continue;
michael@0 354 }
michael@0 355 } else if (pref instanceof PanelsPreferenceCategory) {
michael@0 356 mPanelsPreferenceCategory = (PanelsPreferenceCategory) pref;
michael@0 357 }
michael@0 358 setupPreferences((PreferenceGroup) pref, prefs);
michael@0 359 } else {
michael@0 360 pref.setOnPreferenceChangeListener(this);
michael@0 361 if (!AppConstants.MOZ_UPDATER &&
michael@0 362 PREFS_UPDATER_AUTODOWNLOAD.equals(key)) {
michael@0 363 preferences.removePreference(pref);
michael@0 364 i--;
michael@0 365 continue;
michael@0 366 } else if (AppConstants.RELEASE_BUILD &&
michael@0 367 PREFS_DISPLAY_REFLOW_ON_ZOOM.equals(key)) {
michael@0 368 // Remove UI for reflow on release builds.
michael@0 369 preferences.removePreference(pref);
michael@0 370 i--;
michael@0 371 continue;
michael@0 372 } else if (!AppConstants.MOZ_TELEMETRY_REPORTING &&
michael@0 373 PREFS_TELEMETRY_ENABLED.equals(key)) {
michael@0 374 preferences.removePreference(pref);
michael@0 375 i--;
michael@0 376 continue;
michael@0 377 } else if (!AppConstants.MOZ_SERVICES_HEALTHREPORT &&
michael@0 378 (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(key) ||
michael@0 379 PREFS_HEALTHREPORT_LINK.equals(key))) {
michael@0 380 preferences.removePreference(pref);
michael@0 381 i--;
michael@0 382 continue;
michael@0 383 } else if (!AppConstants.MOZ_CRASHREPORTER &&
michael@0 384 PREFS_CRASHREPORTER_ENABLED.equals(key)) {
michael@0 385 preferences.removePreference(pref);
michael@0 386 i--;
michael@0 387 continue;
michael@0 388 } else if (AppConstants.RELEASE_BUILD && PREFS_GEO_REPORTING.equals(key)) {
michael@0 389 // We don't build wifi/cell tower collection in release builds, so hide the UI.
michael@0 390 preferences.removePreference(pref);
michael@0 391 i--;
michael@0 392 continue;
michael@0 393 } else if (PREFS_DEVTOOLS_REMOTE_ENABLED.equals(key)) {
michael@0 394 final Context thisContext = this;
michael@0 395 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
michael@0 396 @Override
michael@0 397 public boolean onPreferenceClick(Preference preference) {
michael@0 398 // Display toast to remind setting up tcp forwarding.
michael@0 399 if (((CheckBoxPreference) preference).isChecked()) {
michael@0 400 Toast.makeText(thisContext, R.string.devtools_remote_debugging_forward, Toast.LENGTH_SHORT).show();
michael@0 401 }
michael@0 402 return true;
michael@0 403 }
michael@0 404 });
michael@0 405 } else if (PREFS_RESTORE_SESSION.equals(key)) {
michael@0 406 // Set the summary string to the current entry. The summary
michael@0 407 // for other list prefs will be set in the PrefsHelper
michael@0 408 // callback, but since this pref doesn't live in Gecko, we
michael@0 409 // need to handle it separately.
michael@0 410 ListPreference listPref = (ListPreference) pref;
michael@0 411 CharSequence selectedEntry = listPref.getEntry();
michael@0 412 listPref.setSummary(selectedEntry);
michael@0 413 continue;
michael@0 414 } else if (PREFS_SYNC.equals(key) && GeckoProfile.get(this).inGuestMode()) {
michael@0 415 // Don't show sync prefs while in guest mode.
michael@0 416 preferences.removePreference(pref);
michael@0 417 i--;
michael@0 418 continue;
michael@0 419 } else if (PREFS_SEARCH_RESTORE_DEFAULTS.equals(key)) {
michael@0 420 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
michael@0 421 @Override
michael@0 422 public boolean onPreferenceClick(Preference preference) {
michael@0 423 GeckoPreferences.this.restoreDefaultSearchEngines();
michael@0 424 return true;
michael@0 425 }
michael@0 426 });
michael@0 427 } else if (PREFS_HOME_ADD_PANEL.equals(key)) {
michael@0 428 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
michael@0 429 @Override
michael@0 430 public boolean onPreferenceClick(Preference preference) {
michael@0 431 Intent dialogIntent = new Intent(GeckoPreferences.this, HomePanelPicker.class);
michael@0 432 startActivityForResult(dialogIntent, HomePanelPicker.REQUEST_CODE_ADD_PANEL);
michael@0 433 return true;
michael@0 434 }
michael@0 435 });
michael@0 436 }
michael@0 437
michael@0 438 // Some Preference UI elements are not actually preferences,
michael@0 439 // but they require a key to work correctly. For example,
michael@0 440 // "Clear private data" requires a key for its state to be
michael@0 441 // saved when the orientation changes. It uses the
michael@0 442 // "android.not_a_preference.privacy.clear" key - which doesn't
michael@0 443 // exist in Gecko - to satisfy this requirement.
michael@0 444 if (key != null && !key.startsWith(NON_PREF_PREFIX)) {
michael@0 445 prefs.add(key);
michael@0 446 }
michael@0 447 }
michael@0 448 }
michael@0 449 }
michael@0 450
michael@0 451 /**
michael@0 452 * Restore default search engines in Gecko and retrigger a search engine refresh.
michael@0 453 */
michael@0 454 protected void restoreDefaultSearchEngines() {
michael@0 455 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:RestoreDefaults", null));
michael@0 456
michael@0 457 // Send message to Gecko to get engines. SearchPreferenceCategory listens for the response.
michael@0 458 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
michael@0 459 }
michael@0 460
michael@0 461 @Override
michael@0 462 public boolean onOptionsItemSelected(MenuItem item) {
michael@0 463 int itemId = item.getItemId();
michael@0 464 switch (itemId) {
michael@0 465 case android.R.id.home:
michael@0 466 finish();
michael@0 467 return true;
michael@0 468 }
michael@0 469
michael@0 470 // Generated R.id.* apparently aren't constant expressions, so they can't be switched.
michael@0 471 if (itemId == R.id.restore_defaults) {
michael@0 472 restoreDefaultSearchEngines();
michael@0 473 return true;
michael@0 474 }
michael@0 475
michael@0 476 return super.onOptionsItemSelected(item);
michael@0 477 }
michael@0 478
michael@0 479 final private int DIALOG_CREATE_MASTER_PASSWORD = 0;
michael@0 480 final private int DIALOG_REMOVE_MASTER_PASSWORD = 1;
michael@0 481
michael@0 482 public static void setCharEncodingState(boolean enabled) {
michael@0 483 sIsCharEncodingEnabled = enabled;
michael@0 484 }
michael@0 485
michael@0 486 public static boolean getCharEncodingState() {
michael@0 487 return sIsCharEncodingEnabled;
michael@0 488 }
michael@0 489
michael@0 490 public static void broadcastAction(final Context context, final Intent intent) {
michael@0 491 fillIntentWithProfileInfo(context, intent);
michael@0 492 context.sendBroadcast(intent, GlobalConstants.PER_ANDROID_PACKAGE_PERMISSION);
michael@0 493 }
michael@0 494
michael@0 495 /**
michael@0 496 * Broadcast an intent with <code>pref</code>, <code>branch</code>, and
michael@0 497 * <code>enabled</code> extras. This is intended to represent the
michael@0 498 * notification of a preference value to observers.
michael@0 499 *
michael@0 500 * The broadcast will be sent only to receivers registered with the
michael@0 501 * (Fennec-specific) per-Android package permission.
michael@0 502 */
michael@0 503 public static void broadcastPrefAction(final Context context,
michael@0 504 final String action,
michael@0 505 final String pref,
michael@0 506 final boolean value) {
michael@0 507 final Intent intent = new Intent(action)
michael@0 508 .putExtra("pref", pref)
michael@0 509 .putExtra("branch", GeckoSharedPrefs.APP_PREFS_NAME)
michael@0 510 .putExtra("enabled", value);
michael@0 511 broadcastAction(context, intent);
michael@0 512 }
michael@0 513
michael@0 514 private static void fillIntentWithProfileInfo(final Context context, final Intent intent) {
michael@0 515 // There is a race here, but GeckoProfile returns the default profile
michael@0 516 // when Gecko is not explicitly running for a different profile. In a
michael@0 517 // multi-profile world, this will need to be updated (possibly to
michael@0 518 // broadcast settings for all profiles). See Bug 882182.
michael@0 519 GeckoProfile profile = GeckoProfile.get(context);
michael@0 520 if (profile != null) {
michael@0 521 intent.putExtra("profileName", profile.getName())
michael@0 522 .putExtra("profilePath", profile.getDir().getAbsolutePath());
michael@0 523 }
michael@0 524 }
michael@0 525
michael@0 526 /**
michael@0 527 * Broadcast the provided value as the value of the
michael@0 528 * <code>PREFS_ANNOUNCEMENTS_ENABLED</code> pref.
michael@0 529 */
michael@0 530 public static void broadcastAnnouncementsPref(final Context context, final boolean value) {
michael@0 531 broadcastPrefAction(context,
michael@0 532 AnnouncementsConstants.ACTION_ANNOUNCEMENTS_PREF,
michael@0 533 PREFS_ANNOUNCEMENTS_ENABLED,
michael@0 534 value);
michael@0 535 }
michael@0 536
michael@0 537 /**
michael@0 538 * Broadcast the current value of the
michael@0 539 * <code>PREFS_ANNOUNCEMENTS_ENABLED</code> pref.
michael@0 540 */
michael@0 541 public static void broadcastAnnouncementsPref(final Context context) {
michael@0 542 final boolean value = getBooleanPref(context, PREFS_ANNOUNCEMENTS_ENABLED, true);
michael@0 543 broadcastAnnouncementsPref(context, value);
michael@0 544 }
michael@0 545
michael@0 546 /**
michael@0 547 * Broadcast the provided value as the value of the
michael@0 548 * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
michael@0 549 */
michael@0 550 public static void broadcastHealthReportUploadPref(final Context context, final boolean value) {
michael@0 551 broadcastPrefAction(context,
michael@0 552 HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF,
michael@0 553 PREFS_HEALTHREPORT_UPLOAD_ENABLED,
michael@0 554 value);
michael@0 555 }
michael@0 556
michael@0 557 /**
michael@0 558 * Broadcast the current value of the
michael@0 559 * <code>PREFS_HEALTHREPORT_UPLOAD_ENABLED</code> pref.
michael@0 560 */
michael@0 561 public static void broadcastHealthReportUploadPref(final Context context) {
michael@0 562 final boolean value = getBooleanPref(context, PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
michael@0 563 broadcastHealthReportUploadPref(context, value);
michael@0 564 }
michael@0 565
michael@0 566 public static void broadcastHealthReportPrune(final Context context) {
michael@0 567 final Intent intent = new Intent(HealthReportConstants.ACTION_HEALTHREPORT_PRUNE);
michael@0 568 broadcastAction(context, intent);
michael@0 569 }
michael@0 570
michael@0 571 /**
michael@0 572 * Return the value of the named preference in the default preferences file.
michael@0 573 *
michael@0 574 * This corresponds to the storage that backs preferences.xml.
michael@0 575 * @param context a <code>Context</code>; the
michael@0 576 * <code>PreferenceActivity</code> will suffice, but this
michael@0 577 * method is intended to be called from other contexts
michael@0 578 * within the application, not just this <code>Activity</code>.
michael@0 579 * @param name the name of the preference to retrieve.
michael@0 580 * @param def the default value to return if the preference is not present.
michael@0 581 * @return the value of the preference, or the default.
michael@0 582 */
michael@0 583 public static boolean getBooleanPref(final Context context, final String name, boolean def) {
michael@0 584 final SharedPreferences prefs = GeckoSharedPrefs.forApp(context);
michael@0 585 return prefs.getBoolean(name, def);
michael@0 586 }
michael@0 587
michael@0 588 @Override
michael@0 589 public boolean onPreferenceChange(Preference preference, Object newValue) {
michael@0 590 String prefName = preference.getKey();
michael@0 591 if (PREFS_MP_ENABLED.equals(prefName)) {
michael@0 592 showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
michael@0 593
michael@0 594 // We don't want the "use master password" pref to change until the
michael@0 595 // user has gone through the dialog.
michael@0 596 return false;
michael@0 597 } else if (PREFS_MENU_CHAR_ENCODING.equals(prefName)) {
michael@0 598 setCharEncodingState(((String) newValue).equals("true"));
michael@0 599 } else if (PREFS_ANNOUNCEMENTS_ENABLED.equals(prefName)) {
michael@0 600 // Send a broadcast intent to the product announcements service, either to start or
michael@0 601 // to stop the repeated background checks.
michael@0 602 broadcastAnnouncementsPref(this, ((Boolean) newValue).booleanValue());
michael@0 603 } else if (PREFS_UPDATER_AUTODOWNLOAD.equals(prefName)) {
michael@0 604 org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(this, (String) newValue);
michael@0 605 } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(prefName)) {
michael@0 606 // The healthreport pref only lives in Android, so we do not persist
michael@0 607 // to Gecko, but we do broadcast intent to the health report
michael@0 608 // background uploader service, which will start or stop the
michael@0 609 // repeated background upload attempts.
michael@0 610 broadcastHealthReportUploadPref(this, ((Boolean) newValue).booleanValue());
michael@0 611 } else if (PREFS_GEO_REPORTING.equals(prefName)) {
michael@0 612 // Translate boolean value to int for geo reporting pref.
michael@0 613 newValue = ((Boolean) newValue) ? 1 : 0;
michael@0 614 }
michael@0 615
michael@0 616 // Send Gecko-side pref changes to Gecko
michael@0 617 if (!TextUtils.isEmpty(prefName) && !prefName.startsWith(NON_PREF_PREFIX)) {
michael@0 618 PrefsHelper.setPref(prefName, newValue);
michael@0 619 }
michael@0 620
michael@0 621 if (preference instanceof ListPreference) {
michael@0 622 // We need to find the entry for the new value
michael@0 623 int newIndex = ((ListPreference) preference).findIndexOfValue((String) newValue);
michael@0 624 CharSequence newEntry = ((ListPreference) preference).getEntries()[newIndex];
michael@0 625 ((ListPreference) preference).setSummary(newEntry);
michael@0 626 } else if (preference instanceof LinkPreference) {
michael@0 627 setResult(RESULT_CODE_EXIT_SETTINGS);
michael@0 628 finish();
michael@0 629 } else if (preference instanceof FontSizePreference) {
michael@0 630 final FontSizePreference fontSizePref = (FontSizePreference) preference;
michael@0 631 fontSizePref.setSummary(fontSizePref.getSavedFontSizeName());
michael@0 632 }
michael@0 633
michael@0 634 return true;
michael@0 635 }
michael@0 636
michael@0 637 private EditText getTextBox(int aHintText) {
michael@0 638 EditText input = new EditText(this);
michael@0 639 int inputtype = InputType.TYPE_CLASS_TEXT;
michael@0 640 inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
michael@0 641 input.setInputType(inputtype);
michael@0 642
michael@0 643 input.setHint(aHintText);
michael@0 644 return input;
michael@0 645 }
michael@0 646
michael@0 647 private class PasswordTextWatcher implements TextWatcher {
michael@0 648 EditText input1 = null;
michael@0 649 EditText input2 = null;
michael@0 650 AlertDialog dialog = null;
michael@0 651
michael@0 652 PasswordTextWatcher(EditText aInput1, EditText aInput2, AlertDialog aDialog) {
michael@0 653 input1 = aInput1;
michael@0 654 input2 = aInput2;
michael@0 655 dialog = aDialog;
michael@0 656 }
michael@0 657
michael@0 658 @Override
michael@0 659 public void afterTextChanged(Editable s) {
michael@0 660 if (dialog == null)
michael@0 661 return;
michael@0 662
michael@0 663 String text1 = input1.getText().toString();
michael@0 664 String text2 = input2.getText().toString();
michael@0 665 boolean disabled = TextUtils.isEmpty(text1) || TextUtils.isEmpty(text2) || !text1.equals(text2);
michael@0 666 dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
michael@0 667 }
michael@0 668
michael@0 669 @Override
michael@0 670 public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
michael@0 671 @Override
michael@0 672 public void onTextChanged(CharSequence s, int start, int before, int count) { }
michael@0 673 }
michael@0 674
michael@0 675 private class EmptyTextWatcher implements TextWatcher {
michael@0 676 EditText input = null;
michael@0 677 AlertDialog dialog = null;
michael@0 678
michael@0 679 EmptyTextWatcher(EditText aInput, AlertDialog aDialog) {
michael@0 680 input = aInput;
michael@0 681 dialog = aDialog;
michael@0 682 }
michael@0 683
michael@0 684 @Override
michael@0 685 public void afterTextChanged(Editable s) {
michael@0 686 if (dialog == null)
michael@0 687 return;
michael@0 688
michael@0 689 String text = input.getText().toString();
michael@0 690 boolean disabled = TextUtils.isEmpty(text);
michael@0 691 dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!disabled);
michael@0 692 }
michael@0 693
michael@0 694 @Override
michael@0 695 public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
michael@0 696 @Override
michael@0 697 public void onTextChanged(CharSequence s, int start, int before, int count) { }
michael@0 698 }
michael@0 699
michael@0 700 @Override
michael@0 701 protected Dialog onCreateDialog(int id) {
michael@0 702 AlertDialog.Builder builder = new AlertDialog.Builder(this);
michael@0 703 LinearLayout linearLayout = new LinearLayout(this);
michael@0 704 linearLayout.setOrientation(LinearLayout.VERTICAL);
michael@0 705 AlertDialog dialog = null;
michael@0 706 switch(id) {
michael@0 707 case DIALOG_CREATE_MASTER_PASSWORD:
michael@0 708 final EditText input1 = getTextBox(R.string.masterpassword_password);
michael@0 709 final EditText input2 = getTextBox(R.string.masterpassword_confirm);
michael@0 710 linearLayout.addView(input1);
michael@0 711 linearLayout.addView(input2);
michael@0 712
michael@0 713 builder.setTitle(R.string.masterpassword_create_title)
michael@0 714 .setView((View) linearLayout)
michael@0 715 .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
michael@0 716 @Override
michael@0 717 public void onClick(DialogInterface dialog, int which) {
michael@0 718 JSONObject jsonPref = new JSONObject();
michael@0 719 try {
michael@0 720 jsonPref.put("name", PREFS_MP_ENABLED);
michael@0 721 jsonPref.put("type", "string");
michael@0 722 jsonPref.put("value", input1.getText().toString());
michael@0 723
michael@0 724 GeckoEvent event = GeckoEvent.createBroadcastEvent("Preferences:Set", jsonPref.toString());
michael@0 725 GeckoAppShell.sendEventToGecko(event);
michael@0 726 } catch(Exception ex) {
michael@0 727 Log.e(LOGTAG, "Error setting master password", ex);
michael@0 728 }
michael@0 729 return;
michael@0 730 }
michael@0 731 })
michael@0 732 .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
michael@0 733 @Override
michael@0 734 public void onClick(DialogInterface dialog, int which) {
michael@0 735 return;
michael@0 736 }
michael@0 737 });
michael@0 738 dialog = builder.create();
michael@0 739 dialog.setOnShowListener(new DialogInterface.OnShowListener() {
michael@0 740 @Override
michael@0 741 public void onShow(DialogInterface dialog) {
michael@0 742 input1.setText("");
michael@0 743 input2.setText("");
michael@0 744 input1.requestFocus();
michael@0 745 }
michael@0 746 });
michael@0 747
michael@0 748 PasswordTextWatcher watcher = new PasswordTextWatcher(input1, input2, dialog);
michael@0 749 input1.addTextChangedListener((TextWatcher) watcher);
michael@0 750 input2.addTextChangedListener((TextWatcher) watcher);
michael@0 751
michael@0 752 break;
michael@0 753 case DIALOG_REMOVE_MASTER_PASSWORD:
michael@0 754 final EditText input = getTextBox(R.string.masterpassword_password);
michael@0 755 linearLayout.addView(input);
michael@0 756
michael@0 757 builder.setTitle(R.string.masterpassword_remove_title)
michael@0 758 .setView((View) linearLayout)
michael@0 759 .setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
michael@0 760 @Override
michael@0 761 public void onClick(DialogInterface dialog, int which) {
michael@0 762 PrefsHelper.setPref(PREFS_MP_ENABLED, input.getText().toString());
michael@0 763 }
michael@0 764 })
michael@0 765 .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
michael@0 766 @Override
michael@0 767 public void onClick(DialogInterface dialog, int which) {
michael@0 768 return;
michael@0 769 }
michael@0 770 });
michael@0 771 dialog = builder.create();
michael@0 772 dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
michael@0 773 @Override
michael@0 774 public void onDismiss(DialogInterface dialog) {
michael@0 775 input.setText("");
michael@0 776 }
michael@0 777 });
michael@0 778 dialog.setOnShowListener(new DialogInterface.OnShowListener() {
michael@0 779 @Override
michael@0 780 public void onShow(DialogInterface dialog) {
michael@0 781 input.setText("");
michael@0 782 }
michael@0 783 });
michael@0 784 input.addTextChangedListener(new EmptyTextWatcher(input, dialog));
michael@0 785 break;
michael@0 786 default:
michael@0 787 return null;
michael@0 788 }
michael@0 789
michael@0 790 return dialog;
michael@0 791 }
michael@0 792
michael@0 793 // Initialize preferences by requesting the preference values from Gecko
michael@0 794 private int getGeckoPreferences(final PreferenceGroup screen, ArrayList<String> prefs) {
michael@0 795 return PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
michael@0 796 private Preference getField(String prefName) {
michael@0 797 return screen.findPreference(prefName);
michael@0 798 }
michael@0 799
michael@0 800 // Handle v14 TwoStatePreference with backwards compatibility.
michael@0 801 class CheckBoxPrefSetter {
michael@0 802 public void setBooleanPref(Preference preference, boolean value) {
michael@0 803 if ((preference instanceof CheckBoxPreference) &&
michael@0 804 ((CheckBoxPreference) preference).isChecked() != value) {
michael@0 805 ((CheckBoxPreference) preference).setChecked(value);
michael@0 806 }
michael@0 807 }
michael@0 808 }
michael@0 809
michael@0 810 class TwoStatePrefSetter extends CheckBoxPrefSetter {
michael@0 811 @Override
michael@0 812 public void setBooleanPref(Preference preference, boolean value) {
michael@0 813 if ((preference instanceof TwoStatePreference) &&
michael@0 814 ((TwoStatePreference) preference).isChecked() != value) {
michael@0 815 ((TwoStatePreference) preference).setChecked(value);
michael@0 816 }
michael@0 817 }
michael@0 818 }
michael@0 819
michael@0 820 @Override
michael@0 821 public void prefValue(String prefName, final boolean value) {
michael@0 822 final Preference pref = getField(prefName);
michael@0 823 final CheckBoxPrefSetter prefSetter;
michael@0 824 if (Build.VERSION.SDK_INT < 14) {
michael@0 825 prefSetter = new CheckBoxPrefSetter();
michael@0 826 } else {
michael@0 827 prefSetter = new TwoStatePrefSetter();
michael@0 828 }
michael@0 829 ThreadUtils.postToUiThread(new Runnable() {
michael@0 830 public void run() {
michael@0 831 prefSetter.setBooleanPref(pref, value);
michael@0 832 }
michael@0 833 });
michael@0 834 }
michael@0 835
michael@0 836 @Override
michael@0 837 public void prefValue(String prefName, final String value) {
michael@0 838 final Preference pref = getField(prefName);
michael@0 839 if (pref instanceof EditTextPreference) {
michael@0 840 ThreadUtils.postToUiThread(new Runnable() {
michael@0 841 @Override
michael@0 842 public void run() {
michael@0 843 ((EditTextPreference) pref).setText(value);
michael@0 844 }
michael@0 845 });
michael@0 846 } else if (pref instanceof ListPreference) {
michael@0 847 ThreadUtils.postToUiThread(new Runnable() {
michael@0 848 @Override
michael@0 849 public void run() {
michael@0 850 ((ListPreference) pref).setValue(value);
michael@0 851 // Set the summary string to the current entry
michael@0 852 CharSequence selectedEntry = ((ListPreference) pref).getEntry();
michael@0 853 ((ListPreference) pref).setSummary(selectedEntry);
michael@0 854 }
michael@0 855 });
michael@0 856 } else if (pref instanceof FontSizePreference) {
michael@0 857 final FontSizePreference fontSizePref = (FontSizePreference) pref;
michael@0 858 fontSizePref.setSavedFontSize(value);
michael@0 859 final String fontSizeName = fontSizePref.getSavedFontSizeName();
michael@0 860 ThreadUtils.postToUiThread(new Runnable() {
michael@0 861 @Override
michael@0 862 public void run() {
michael@0 863 fontSizePref.setSummary(fontSizeName); // Ex: "Small".
michael@0 864 }
michael@0 865 });
michael@0 866 }
michael@0 867 }
michael@0 868
michael@0 869 @Override
michael@0 870 public void prefValue(String prefName, final int value) {
michael@0 871 final Preference pref = getField(prefName);
michael@0 872 final CheckBoxPrefSetter prefSetter;
michael@0 873 if (PREFS_GEO_REPORTING.equals(prefName)) {
michael@0 874 if (Build.VERSION.SDK_INT < 14) {
michael@0 875 prefSetter = new CheckBoxPrefSetter();
michael@0 876 } else {
michael@0 877 prefSetter = new TwoStatePrefSetter();
michael@0 878 }
michael@0 879 ThreadUtils.postToUiThread(new Runnable() {
michael@0 880 @Override
michael@0 881 public void run() {
michael@0 882 prefSetter.setBooleanPref(pref, value == 1);
michael@0 883 }
michael@0 884 });
michael@0 885 } else {
michael@0 886 Log.w(LOGTAG, "Unhandled int value for pref [" + pref + "]");
michael@0 887 }
michael@0 888 }
michael@0 889
michael@0 890 @Override
michael@0 891 public boolean isObserver() {
michael@0 892 return true;
michael@0 893 }
michael@0 894
michael@0 895 @Override
michael@0 896 public void finish() {
michael@0 897 // enable all preferences once we have them from gecko
michael@0 898 ThreadUtils.postToUiThread(new Runnable() {
michael@0 899 @Override
michael@0 900 public void run() {
michael@0 901 screen.setEnabled(true);
michael@0 902 }
michael@0 903 });
michael@0 904 }
michael@0 905 });
michael@0 906 }
michael@0 907
michael@0 908 private void registerEventListener(String event) {
michael@0 909 GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
michael@0 910 }
michael@0 911
michael@0 912 private void unregisterEventListener(String event) {
michael@0 913 GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
michael@0 914 }
michael@0 915
michael@0 916 @Override
michael@0 917 public boolean isGeckoActivityOpened() {
michael@0 918 return false;
michael@0 919 }
michael@0 920
michael@0 921 /**
michael@0 922 * Given an Intent instance, add extras to specify which settings section to
michael@0 923 * open.
michael@0 924 *
michael@0 925 * resource should be a valid Android XML resource identifier.
michael@0 926 *
michael@0 927 * The mechanism to open a section differs based on Android version.
michael@0 928 */
michael@0 929 public static void setResourceToOpen(final Intent intent, final String resource) {
michael@0 930 if (intent == null) {
michael@0 931 throw new IllegalArgumentException("intent must not be null");
michael@0 932 }
michael@0 933 if (resource == null) {
michael@0 934 return;
michael@0 935 }
michael@0 936
michael@0 937 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
michael@0 938 intent.putExtra("resource", resource);
michael@0 939 } else {
michael@0 940 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, GeckoPreferenceFragment.class.getName());
michael@0 941
michael@0 942 Bundle fragmentArgs = new Bundle();
michael@0 943 fragmentArgs.putString("resource", resource);
michael@0 944 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
michael@0 945 }
michael@0 946 }
michael@0 947 }

mercurial