mobile/android/base/fxa/activities/FxAccountStatusFragment.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko.fxa.activities;
michael@0 6
michael@0 7 import java.util.HashMap;
michael@0 8 import java.util.Map;
michael@0 9 import java.util.Set;
michael@0 10
michael@0 11 import org.mozilla.gecko.R;
michael@0 12 import org.mozilla.gecko.background.common.log.Logger;
michael@0 13 import org.mozilla.gecko.background.preferences.PreferenceFragment;
michael@0 14 import org.mozilla.gecko.fxa.FirefoxAccounts;
michael@0 15 import org.mozilla.gecko.fxa.FxAccountConstants;
michael@0 16 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
michael@0 17 import org.mozilla.gecko.fxa.login.Married;
michael@0 18 import org.mozilla.gecko.fxa.login.State;
michael@0 19 import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
michael@0 20 import org.mozilla.gecko.sync.SyncConfiguration;
michael@0 21
michael@0 22 import android.accounts.Account;
michael@0 23 import android.content.ContentResolver;
michael@0 24 import android.content.Context;
michael@0 25 import android.content.Intent;
michael@0 26 import android.content.SharedPreferences;
michael@0 27 import android.os.Bundle;
michael@0 28 import android.os.Handler;
michael@0 29 import android.preference.CheckBoxPreference;
michael@0 30 import android.preference.Preference;
michael@0 31 import android.preference.Preference.OnPreferenceClickListener;
michael@0 32 import android.preference.PreferenceCategory;
michael@0 33 import android.preference.PreferenceScreen;
michael@0 34
michael@0 35 /**
michael@0 36 * A fragment that displays the status of an AndroidFxAccount.
michael@0 37 * <p>
michael@0 38 * The owning activity is responsible for providing an AndroidFxAccount at
michael@0 39 * appropriate times.
michael@0 40 */
michael@0 41 public class FxAccountStatusFragment extends PreferenceFragment implements OnPreferenceClickListener {
michael@0 42 private static final String LOG_TAG = FxAccountStatusFragment.class.getSimpleName();
michael@0 43
michael@0 44 // When a checkbox is toggled, wait 5 seconds (for other checkbox actions)
michael@0 45 // before trying to sync. Should we kill off the fragment before the sync
michael@0 46 // request happens, that's okay: the runnable will run if the UI thread is
michael@0 47 // still around to service it, and since we're not updating any UI, we'll just
michael@0 48 // schedule the sync as usual. See also comment below about garbage
michael@0 49 // collection.
michael@0 50 private static final long DELAY_IN_MILLISECONDS_BEFORE_REQUESTING_SYNC = 5 * 1000;
michael@0 51
michael@0 52 protected Preference emailPreference;
michael@0 53
michael@0 54 protected Preference needsPasswordPreference;
michael@0 55 protected Preference needsUpgradePreference;
michael@0 56 protected Preference needsVerificationPreference;
michael@0 57 protected Preference needsMasterSyncAutomaticallyEnabledPreference;
michael@0 58 protected Preference needsAccountEnabledPreference;
michael@0 59
michael@0 60 protected PreferenceCategory syncCategory;
michael@0 61
michael@0 62 protected CheckBoxPreference bookmarksPreference;
michael@0 63 protected CheckBoxPreference historyPreference;
michael@0 64 protected CheckBoxPreference tabsPreference;
michael@0 65 protected CheckBoxPreference passwordsPreference;
michael@0 66
michael@0 67 protected volatile AndroidFxAccount fxAccount;
michael@0 68
michael@0 69 // Used to post delayed sync requests.
michael@0 70 protected Handler handler;
michael@0 71
michael@0 72 // Member variable so that re-posting pushes back the already posted instance.
michael@0 73 // This Runnable references the fxAccount above, but it is not specific to a
michael@0 74 // single account. (That is, it does not capture a single account instance.)
michael@0 75 protected Runnable requestSyncRunnable;
michael@0 76
michael@0 77 protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
michael@0 78
michael@0 79 protected Preference ensureFindPreference(String key) {
michael@0 80 Preference preference = findPreference(key);
michael@0 81 if (preference == null) {
michael@0 82 throw new IllegalStateException("Could not find preference with key: " + key);
michael@0 83 }
michael@0 84 return preference;
michael@0 85 }
michael@0 86
michael@0 87 @Override
michael@0 88 public void onCreate(Bundle savedInstanceState) {
michael@0 89 super.onCreate(savedInstanceState);
michael@0 90 addPreferencesFromResource(R.xml.fxaccount_status_prefscreen);
michael@0 91
michael@0 92 emailPreference = ensureFindPreference("email");
michael@0 93
michael@0 94 needsPasswordPreference = ensureFindPreference("needs_credentials");
michael@0 95 needsUpgradePreference = ensureFindPreference("needs_upgrade");
michael@0 96 needsVerificationPreference = ensureFindPreference("needs_verification");
michael@0 97 needsMasterSyncAutomaticallyEnabledPreference = ensureFindPreference("needs_master_sync_automatically_enabled");
michael@0 98 needsAccountEnabledPreference = ensureFindPreference("needs_account_enabled");
michael@0 99
michael@0 100 syncCategory = (PreferenceCategory) ensureFindPreference("sync_category");
michael@0 101
michael@0 102 bookmarksPreference = (CheckBoxPreference) ensureFindPreference("bookmarks");
michael@0 103 historyPreference = (CheckBoxPreference) ensureFindPreference("history");
michael@0 104 tabsPreference = (CheckBoxPreference) ensureFindPreference("tabs");
michael@0 105 passwordsPreference = (CheckBoxPreference) ensureFindPreference("passwords");
michael@0 106
michael@0 107 if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
michael@0 108 removeDebugButtons();
michael@0 109 } else {
michael@0 110 connectDebugButtons();
michael@0 111 }
michael@0 112
michael@0 113 needsPasswordPreference.setOnPreferenceClickListener(this);
michael@0 114 needsVerificationPreference.setOnPreferenceClickListener(this);
michael@0 115 needsAccountEnabledPreference.setOnPreferenceClickListener(this);
michael@0 116
michael@0 117 bookmarksPreference.setOnPreferenceClickListener(this);
michael@0 118 historyPreference.setOnPreferenceClickListener(this);
michael@0 119 tabsPreference.setOnPreferenceClickListener(this);
michael@0 120 passwordsPreference.setOnPreferenceClickListener(this);
michael@0 121 }
michael@0 122
michael@0 123 /**
michael@0 124 * We intentionally don't refresh here. Our owning activity is responsible for
michael@0 125 * providing an AndroidFxAccount to our refresh method in its onResume method.
michael@0 126 */
michael@0 127 @Override
michael@0 128 public void onResume() {
michael@0 129 super.onResume();
michael@0 130 }
michael@0 131
michael@0 132 @Override
michael@0 133 public boolean onPreferenceClick(Preference preference) {
michael@0 134 if (preference == needsPasswordPreference) {
michael@0 135 Intent intent = new Intent(getActivity(), FxAccountUpdateCredentialsActivity.class);
michael@0 136 // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
michael@0 137 // the soft keyboard not being shown for the started activity. Why, Android, why?
michael@0 138 intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
michael@0 139 startActivity(intent);
michael@0 140
michael@0 141 return true;
michael@0 142 }
michael@0 143
michael@0 144 if (preference == needsVerificationPreference) {
michael@0 145 FxAccountConfirmAccountActivity.resendCode(getActivity().getApplicationContext(), fxAccount);
michael@0 146
michael@0 147 Intent intent = new Intent(getActivity(), FxAccountConfirmAccountActivity.class);
michael@0 148 // Per http://stackoverflow.com/a/8992365, this triggers a known bug with
michael@0 149 // the soft keyboard not being shown for the started activity. Why, Android, why?
michael@0 150 intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
michael@0 151 startActivity(intent);
michael@0 152
michael@0 153 return true;
michael@0 154 }
michael@0 155
michael@0 156 if (preference == needsAccountEnabledPreference) {
michael@0 157 fxAccount.enableSyncing();
michael@0 158 refresh();
michael@0 159
michael@0 160 return true;
michael@0 161 }
michael@0 162
michael@0 163 if (preference == bookmarksPreference ||
michael@0 164 preference == historyPreference ||
michael@0 165 preference == passwordsPreference ||
michael@0 166 preference == tabsPreference) {
michael@0 167 saveEngineSelections();
michael@0 168 return true;
michael@0 169 }
michael@0 170
michael@0 171 return false;
michael@0 172 }
michael@0 173
michael@0 174 protected void setCheckboxesEnabled(boolean enabled) {
michael@0 175 bookmarksPreference.setEnabled(enabled);
michael@0 176 historyPreference.setEnabled(enabled);
michael@0 177 tabsPreference.setEnabled(enabled);
michael@0 178 passwordsPreference.setEnabled(enabled);
michael@0 179 }
michael@0 180
michael@0 181 /**
michael@0 182 * Show at most one error preference, hiding all others.
michael@0 183 *
michael@0 184 * @param errorPreferenceToShow
michael@0 185 * single error preference to show; if null, hide all error preferences
michael@0 186 */
michael@0 187 protected void showOnlyOneErrorPreference(Preference errorPreferenceToShow) {
michael@0 188 final Preference[] errorPreferences = new Preference[] {
michael@0 189 this.needsPasswordPreference,
michael@0 190 this.needsUpgradePreference,
michael@0 191 this.needsVerificationPreference,
michael@0 192 this.needsMasterSyncAutomaticallyEnabledPreference,
michael@0 193 this.needsAccountEnabledPreference,
michael@0 194 };
michael@0 195 for (Preference errorPreference : errorPreferences) {
michael@0 196 final boolean currentlyShown = null != findPreference(errorPreference.getKey());
michael@0 197 final boolean shouldBeShown = errorPreference == errorPreferenceToShow;
michael@0 198 if (currentlyShown == shouldBeShown) {
michael@0 199 continue;
michael@0 200 }
michael@0 201 if (shouldBeShown) {
michael@0 202 syncCategory.addPreference(errorPreference);
michael@0 203 } else {
michael@0 204 syncCategory.removePreference(errorPreference);
michael@0 205 }
michael@0 206 }
michael@0 207 }
michael@0 208
michael@0 209 protected void showNeedsPassword() {
michael@0 210 syncCategory.setTitle(R.string.fxaccount_status_sync);
michael@0 211 showOnlyOneErrorPreference(needsPasswordPreference);
michael@0 212 setCheckboxesEnabled(false);
michael@0 213 }
michael@0 214
michael@0 215 protected void showNeedsUpgrade() {
michael@0 216 syncCategory.setTitle(R.string.fxaccount_status_sync);
michael@0 217 showOnlyOneErrorPreference(needsUpgradePreference);
michael@0 218 setCheckboxesEnabled(false);
michael@0 219 }
michael@0 220
michael@0 221 protected void showNeedsVerification() {
michael@0 222 syncCategory.setTitle(R.string.fxaccount_status_sync);
michael@0 223 showOnlyOneErrorPreference(needsVerificationPreference);
michael@0 224 setCheckboxesEnabled(false);
michael@0 225 }
michael@0 226
michael@0 227 protected void showNeedsMasterSyncAutomaticallyEnabled() {
michael@0 228 syncCategory.setTitle(R.string.fxaccount_status_sync);
michael@0 229 showOnlyOneErrorPreference(needsMasterSyncAutomaticallyEnabledPreference);
michael@0 230 setCheckboxesEnabled(false);
michael@0 231 }
michael@0 232
michael@0 233 protected void showNeedsAccountEnabled() {
michael@0 234 syncCategory.setTitle(R.string.fxaccount_status_sync);
michael@0 235 showOnlyOneErrorPreference(needsAccountEnabledPreference);
michael@0 236 setCheckboxesEnabled(false);
michael@0 237 }
michael@0 238
michael@0 239 protected void showConnected() {
michael@0 240 syncCategory.setTitle(R.string.fxaccount_status_sync_enabled);
michael@0 241 showOnlyOneErrorPreference(null);
michael@0 242 setCheckboxesEnabled(true);
michael@0 243 }
michael@0 244
michael@0 245 protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener {
michael@0 246 protected final Runnable refreshRunnable = new Runnable() {
michael@0 247 @Override
michael@0 248 public void run() {
michael@0 249 refresh();
michael@0 250 }
michael@0 251 };
michael@0 252
michael@0 253 @Override
michael@0 254 public Context getContext() {
michael@0 255 return FxAccountStatusFragment.this.getActivity();
michael@0 256 }
michael@0 257
michael@0 258 @Override
michael@0 259 public Account getAccount() {
michael@0 260 return fxAccount.getAndroidAccount();
michael@0 261 }
michael@0 262
michael@0 263 @Override
michael@0 264 public void onSyncStarted() {
michael@0 265 if (fxAccount == null) {
michael@0 266 return;
michael@0 267 }
michael@0 268 Logger.info(LOG_TAG, "Got sync started message; refreshing.");
michael@0 269 getActivity().runOnUiThread(refreshRunnable);
michael@0 270 }
michael@0 271
michael@0 272 @Override
michael@0 273 public void onSyncFinished() {
michael@0 274 if (fxAccount == null) {
michael@0 275 return;
michael@0 276 }
michael@0 277 Logger.info(LOG_TAG, "Got sync finished message; refreshing.");
michael@0 278 getActivity().runOnUiThread(refreshRunnable);
michael@0 279 }
michael@0 280 }
michael@0 281
michael@0 282 /**
michael@0 283 * Notify the fragment that a new AndroidFxAccount instance is current.
michael@0 284 * <p>
michael@0 285 * <b>Important:</b> call this method on the UI thread!
michael@0 286 * <p>
michael@0 287 * In future, this might be a Loader.
michael@0 288 *
michael@0 289 * @param fxAccount new instance.
michael@0 290 */
michael@0 291 public void refresh(AndroidFxAccount fxAccount) {
michael@0 292 if (fxAccount == null) {
michael@0 293 throw new IllegalArgumentException("fxAccount must not be null");
michael@0 294 }
michael@0 295 this.fxAccount = fxAccount;
michael@0 296
michael@0 297 handler = new Handler(); // Attached to current (assumed to be UI) thread.
michael@0 298
michael@0 299 // Runnable is not specific to one Firefox Account. This runnable will keep
michael@0 300 // a reference to this fragment alive, but we expect posted runnables to be
michael@0 301 // serviced very quickly, so this is not an issue.
michael@0 302 requestSyncRunnable = new RequestSyncRunnable();
michael@0 303
michael@0 304 // We would very much like register these status observers in bookended
michael@0 305 // onResume/onPause calls, but because the Fragment gets onResume during the
michael@0 306 // Activity's super.onResume, it hasn't yet been told its Firefox Account.
michael@0 307 // So we register the observer here (and remove it in onPause), and open
michael@0 308 // ourselves to the possibility that we don't have properly paired
michael@0 309 // register/unregister calls.
michael@0 310 FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusDelegate);
michael@0 311
michael@0 312 refresh();
michael@0 313 }
michael@0 314
michael@0 315 @Override
michael@0 316 public void onPause() {
michael@0 317 super.onPause();
michael@0 318 FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate);
michael@0 319 }
michael@0 320
michael@0 321 protected void refresh() {
michael@0 322 // refresh is called from our onResume, which can happen before the owning
michael@0 323 // Activity tells us about an account (via our public
michael@0 324 // refresh(AndroidFxAccount) method).
michael@0 325 if (fxAccount == null) {
michael@0 326 throw new IllegalArgumentException("fxAccount must not be null");
michael@0 327 }
michael@0 328
michael@0 329 emailPreference.setTitle(fxAccount.getEmail());
michael@0 330
michael@0 331 try {
michael@0 332 // There are error states determined by Android, not the login state
michael@0 333 // machine, and we have a chance to present these states here. We handle
michael@0 334 // them specially, since we can't surface these states as part of syncing,
michael@0 335 // because they generally stop syncs from happening regularly.
michael@0 336
michael@0 337 // The action to enable syncing the Firefox Account doesn't require
michael@0 338 // leaving this activity, so let's present it first.
michael@0 339 final boolean isSyncing = fxAccount.isSyncing();
michael@0 340 if (!isSyncing) {
michael@0 341 showNeedsAccountEnabled();
michael@0 342 return;
michael@0 343 }
michael@0 344
michael@0 345 // Interrogate the Firefox Account's state.
michael@0 346 State state = fxAccount.getState();
michael@0 347 switch (state.getNeededAction()) {
michael@0 348 case NeedsUpgrade:
michael@0 349 showNeedsUpgrade();
michael@0 350 break;
michael@0 351 case NeedsPassword:
michael@0 352 showNeedsPassword();
michael@0 353 break;
michael@0 354 case NeedsVerification:
michael@0 355 showNeedsVerification();
michael@0 356 break;
michael@0 357 default:
michael@0 358 showConnected();
michael@0 359 }
michael@0 360
michael@0 361 // We check for the master setting last, since it is not strictly
michael@0 362 // necessary for the user to address this error state: it's really a
michael@0 363 // warning state. We surface it for the user's convenience, and to prevent
michael@0 364 // confused folks wondering why Sync is not working at all.
michael@0 365 final boolean masterSyncAutomatically = ContentResolver.getMasterSyncAutomatically();
michael@0 366 if (!masterSyncAutomatically) {
michael@0 367 showNeedsMasterSyncAutomaticallyEnabled();
michael@0 368 return;
michael@0 369 }
michael@0 370 } finally {
michael@0 371 // No matter our state, we should update the checkboxes.
michael@0 372 updateSelectedEngines();
michael@0 373 }
michael@0 374 }
michael@0 375
michael@0 376 /**
michael@0 377 * Query shared prefs for the current engine state, and update the UI
michael@0 378 * accordingly.
michael@0 379 * <p>
michael@0 380 * In future, we might want this to be on a background thread, or implemented
michael@0 381 * as a Loader.
michael@0 382 */
michael@0 383 protected void updateSelectedEngines() {
michael@0 384 try {
michael@0 385 SharedPreferences syncPrefs = fxAccount.getSyncPrefs();
michael@0 386 Map<String, Boolean> engines = SyncConfiguration.getUserSelectedEngines(syncPrefs);
michael@0 387 if (engines != null) {
michael@0 388 bookmarksPreference.setChecked(engines.containsKey("bookmarks") && engines.get("bookmarks"));
michael@0 389 historyPreference.setChecked(engines.containsKey("history") && engines.get("history"));
michael@0 390 passwordsPreference.setChecked(engines.containsKey("passwords") && engines.get("passwords"));
michael@0 391 tabsPreference.setChecked(engines.containsKey("tabs") && engines.get("tabs"));
michael@0 392 return;
michael@0 393 }
michael@0 394
michael@0 395 // We don't have user specified preferences. Perhaps we have seen a meta/global?
michael@0 396 Set<String> enabledNames = SyncConfiguration.getEnabledEngineNames(syncPrefs);
michael@0 397 if (enabledNames != null) {
michael@0 398 bookmarksPreference.setChecked(enabledNames.contains("bookmarks"));
michael@0 399 historyPreference.setChecked(enabledNames.contains("history"));
michael@0 400 passwordsPreference.setChecked(enabledNames.contains("passwords"));
michael@0 401 tabsPreference.setChecked(enabledNames.contains("tabs"));
michael@0 402 return;
michael@0 403 }
michael@0 404
michael@0 405 // Okay, we don't have userSelectedEngines or enabledEngines. That means
michael@0 406 // the user hasn't specified to begin with, we haven't specified here, and
michael@0 407 // we haven't already seen, Sync engines. We don't know our state, so
michael@0 408 // let's check everything (the default) and disable everything.
michael@0 409 bookmarksPreference.setChecked(true);
michael@0 410 historyPreference.setChecked(true);
michael@0 411 passwordsPreference.setChecked(true);
michael@0 412 tabsPreference.setChecked(true);
michael@0 413 setCheckboxesEnabled(false);
michael@0 414 } catch (Exception e) {
michael@0 415 Logger.warn(LOG_TAG, "Got exception getting engines to select; ignoring.", e);
michael@0 416 return;
michael@0 417 }
michael@0 418 }
michael@0 419
michael@0 420 /**
michael@0 421 * Persist engine selections to local shared preferences, and request a sync
michael@0 422 * to persist selections to remote storage.
michael@0 423 */
michael@0 424 protected void saveEngineSelections() {
michael@0 425 final Map<String, Boolean> engineSelections = new HashMap<String, Boolean>();
michael@0 426 engineSelections.put("bookmarks", bookmarksPreference.isChecked());
michael@0 427 engineSelections.put("history", historyPreference.isChecked());
michael@0 428 engineSelections.put("passwords", passwordsPreference.isChecked());
michael@0 429 engineSelections.put("tabs", tabsPreference.isChecked());
michael@0 430
michael@0 431 // No GlobalSession.config, so store directly to shared prefs. We do this on
michael@0 432 // a background thread to avoid IO on the main thread and strict mode
michael@0 433 // warnings.
michael@0 434 new Thread(new PersistEngineSelectionsRunnable(engineSelections)).start();
michael@0 435 }
michael@0 436
michael@0 437 protected void requestDelayedSync() {
michael@0 438 Logger.info(LOG_TAG, "Posting a delayed request for a sync sometime soon.");
michael@0 439 handler.removeCallbacks(requestSyncRunnable);
michael@0 440 handler.postDelayed(requestSyncRunnable, DELAY_IN_MILLISECONDS_BEFORE_REQUESTING_SYNC);
michael@0 441 }
michael@0 442
michael@0 443 /**
michael@0 444 * Remove all traces of debug buttons. By default, no debug buttons are shown.
michael@0 445 */
michael@0 446 protected void removeDebugButtons() {
michael@0 447 final PreferenceScreen statusScreen = (PreferenceScreen) ensureFindPreference("status_screen");
michael@0 448 final PreferenceCategory debugCategory = (PreferenceCategory) ensureFindPreference("debug_category");
michael@0 449 statusScreen.removePreference(debugCategory);
michael@0 450 }
michael@0 451
michael@0 452 /**
michael@0 453 * A Runnable that persists engine selections to shared prefs, and then
michael@0 454 * requests a delayed sync.
michael@0 455 * <p>
michael@0 456 * References the member <code>fxAccount</code> and is specific to the Android
michael@0 457 * account associated to that account.
michael@0 458 */
michael@0 459 protected class PersistEngineSelectionsRunnable implements Runnable {
michael@0 460 private final Map<String, Boolean> engineSelections;
michael@0 461
michael@0 462 protected PersistEngineSelectionsRunnable(Map<String, Boolean> engineSelections) {
michael@0 463 this.engineSelections = engineSelections;
michael@0 464 }
michael@0 465
michael@0 466 @Override
michael@0 467 public void run() {
michael@0 468 try {
michael@0 469 // Name shadowing -- do you like it, or do you love it?
michael@0 470 AndroidFxAccount fxAccount = FxAccountStatusFragment.this.fxAccount;
michael@0 471 if (fxAccount == null) {
michael@0 472 return;
michael@0 473 }
michael@0 474 Logger.info(LOG_TAG, "Persisting engine selections: " + engineSelections.toString());
michael@0 475 SyncConfiguration.storeSelectedEnginesToPrefs(fxAccount.getSyncPrefs(), engineSelections);
michael@0 476 requestDelayedSync();
michael@0 477 } catch (Exception e) {
michael@0 478 Logger.warn(LOG_TAG, "Got exception persisting selected engines; ignoring.", e);
michael@0 479 return;
michael@0 480 }
michael@0 481 }
michael@0 482 }
michael@0 483
michael@0 484 /**
michael@0 485 * A Runnable that requests a sync.
michael@0 486 * <p>
michael@0 487 * References the member <code>fxAccount</code>, but is not specific to the
michael@0 488 * Android account associated to that account.
michael@0 489 */
michael@0 490 protected class RequestSyncRunnable implements Runnable {
michael@0 491 @Override
michael@0 492 public void run() {
michael@0 493 // Name shadowing -- do you like it, or do you love it?
michael@0 494 AndroidFxAccount fxAccount = FxAccountStatusFragment.this.fxAccount;
michael@0 495 if (fxAccount == null) {
michael@0 496 return;
michael@0 497 }
michael@0 498 Logger.info(LOG_TAG, "Requesting a sync sometime soon.");
michael@0 499 fxAccount.requestSync();
michael@0 500 }
michael@0 501 }
michael@0 502
michael@0 503 /**
michael@0 504 * A separate listener to separate debug logic from main code paths.
michael@0 505 */
michael@0 506 protected class DebugPreferenceClickListener implements OnPreferenceClickListener {
michael@0 507 @Override
michael@0 508 public boolean onPreferenceClick(Preference preference) {
michael@0 509 final String key = preference.getKey();
michael@0 510 if ("debug_refresh".equals(key)) {
michael@0 511 Logger.info(LOG_TAG, "Refreshing.");
michael@0 512 refresh();
michael@0 513 } else if ("debug_dump".equals(key)) {
michael@0 514 fxAccount.dump();
michael@0 515 } else if ("debug_force_sync".equals(key)) {
michael@0 516 Logger.info(LOG_TAG, "Force syncing.");
michael@0 517 fxAccount.requestSync(FirefoxAccounts.FORCE);
michael@0 518 // No sense refreshing, since the sync will complete in the future.
michael@0 519 } else if ("debug_forget_certificate".equals(key)) {
michael@0 520 State state = fxAccount.getState();
michael@0 521 try {
michael@0 522 Married married = (Married) state;
michael@0 523 Logger.info(LOG_TAG, "Moving to Cohabiting state: Forgetting certificate.");
michael@0 524 fxAccount.setState(married.makeCohabitingState());
michael@0 525 refresh();
michael@0 526 } catch (ClassCastException e) {
michael@0 527 Logger.info(LOG_TAG, "Not in Married state; can't forget certificate.");
michael@0 528 // Ignore.
michael@0 529 }
michael@0 530 } else if ("debug_require_password".equals(key)) {
michael@0 531 Logger.info(LOG_TAG, "Moving to Separated state: Forgetting password.");
michael@0 532 State state = fxAccount.getState();
michael@0 533 fxAccount.setState(state.makeSeparatedState());
michael@0 534 refresh();
michael@0 535 } else if ("debug_require_upgrade".equals(key)) {
michael@0 536 Logger.info(LOG_TAG, "Moving to Doghouse state: Requiring upgrade.");
michael@0 537 State state = fxAccount.getState();
michael@0 538 fxAccount.setState(state.makeDoghouseState());
michael@0 539 refresh();
michael@0 540 } else {
michael@0 541 return false;
michael@0 542 }
michael@0 543 return true;
michael@0 544 }
michael@0 545 }
michael@0 546
michael@0 547 /**
michael@0 548 * Iterate through debug buttons, adding a special deubg preference click
michael@0 549 * listener to each of them.
michael@0 550 */
michael@0 551 protected void connectDebugButtons() {
michael@0 552 // Separate listener to really separate debug logic from main code paths.
michael@0 553 final OnPreferenceClickListener listener = new DebugPreferenceClickListener();
michael@0 554
michael@0 555 // We don't want to use Android resource strings for debug UI, so we just
michael@0 556 // use the keys throughout.
michael@0 557 final Preference debugCategory = ensureFindPreference("debug_category");
michael@0 558 debugCategory.setTitle(debugCategory.getKey());
michael@0 559
michael@0 560 String[] debugKeys = new String[] {
michael@0 561 "debug_refresh",
michael@0 562 "debug_dump",
michael@0 563 "debug_force_sync",
michael@0 564 "debug_forget_certificate",
michael@0 565 "debug_require_password",
michael@0 566 "debug_require_upgrade" };
michael@0 567 for (String debugKey : debugKeys) {
michael@0 568 final Preference button = ensureFindPreference(debugKey);
michael@0 569 button.setTitle(debugKey); // Not very friendly, but this is for debugging only!
michael@0 570 button.setOnPreferenceClickListener(listener);
michael@0 571 }
michael@0 572 }
michael@0 573 }

mercurial