1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,101 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.fxa.sync; 1.9 + 1.10 +import java.util.Map; 1.11 +import java.util.Map.Entry; 1.12 +import java.util.WeakHashMap; 1.13 + 1.14 +import org.mozilla.gecko.fxa.FirefoxAccounts; 1.15 +import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; 1.16 + 1.17 +import android.content.ContentResolver; 1.18 +import android.content.SyncStatusObserver; 1.19 + 1.20 +/** 1.21 + * Abstract away some details of Android's SyncStatusObserver. 1.22 + * <p> 1.23 + * Provides a simplified sync started/sync finished delegate. 1.24 + */ 1.25 +public class FxAccountSyncStatusHelper implements SyncStatusObserver { 1.26 + @SuppressWarnings("unused") 1.27 + private static final String LOG_TAG = FxAccountSyncStatusHelper.class.getSimpleName(); 1.28 + 1.29 + protected static FxAccountSyncStatusHelper sInstance = null; 1.30 + 1.31 + public synchronized static FxAccountSyncStatusHelper getInstance() { 1.32 + if (sInstance == null) { 1.33 + sInstance = new FxAccountSyncStatusHelper(); 1.34 + } 1.35 + return sInstance; 1.36 + } 1.37 + 1.38 + // Used to unregister this as a listener. 1.39 + protected Object handle = null; 1.40 + 1.41 + // Maps delegates to whether their underlying Android account was syncing the 1.42 + // last time we observed a status change. 1.43 + protected Map<FirefoxAccounts.SyncStatusListener, Boolean> delegates = new WeakHashMap<FirefoxAccounts.SyncStatusListener, Boolean>(); 1.44 + 1.45 + @Override 1.46 + public synchronized void onStatusChanged(int which) { 1.47 + for (Entry<FirefoxAccounts.SyncStatusListener, Boolean> entry : delegates.entrySet()) { 1.48 + final FirefoxAccounts.SyncStatusListener delegate = entry.getKey(); 1.49 + final AndroidFxAccount fxAccount = new AndroidFxAccount(delegate.getContext(), delegate.getAccount()); 1.50 + final boolean active = fxAccount.isCurrentlySyncing(); 1.51 + // Remember for later. 1.52 + boolean wasActiveLastTime = entry.getValue(); 1.53 + // It's okay to update the value of an entry while iterating the entrySet. 1.54 + entry.setValue(active); 1.55 + 1.56 + if (active && !wasActiveLastTime) { 1.57 + // We've started a sync. 1.58 + delegate.onSyncStarted(); 1.59 + } 1.60 + if (!active && wasActiveLastTime) { 1.61 + // We've finished a sync. 1.62 + delegate.onSyncFinished(); 1.63 + } 1.64 + } 1.65 + } 1.66 + 1.67 + protected void addListener() { 1.68 + final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE; 1.69 + if (this.handle != null) { 1.70 + throw new IllegalStateException("Already registered this as an observer?"); 1.71 + } 1.72 + this.handle = ContentResolver.addStatusChangeListener(mask, this); 1.73 + } 1.74 + 1.75 + protected void removeListener() { 1.76 + Object handle = this.handle; 1.77 + this.handle = null; 1.78 + if (handle != null) { 1.79 + ContentResolver.removeStatusChangeListener(handle); 1.80 + } 1.81 + } 1.82 + 1.83 + public synchronized void startObserving(FirefoxAccounts.SyncStatusListener delegate) { 1.84 + if (delegate == null) { 1.85 + throw new IllegalArgumentException("delegate must not be null"); 1.86 + } 1.87 + if (delegates.containsKey(delegate)) { 1.88 + return; 1.89 + } 1.90 + // If we are the first delegate to the party, start listening. 1.91 + if (delegates.isEmpty()) { 1.92 + addListener(); 1.93 + } 1.94 + delegates.put(delegate, Boolean.FALSE); 1.95 + } 1.96 + 1.97 + public synchronized void stopObserving(FirefoxAccounts.SyncStatusListener delegate) { 1.98 + delegates.remove(delegate); 1.99 + // If we are the last delegate leaving the party, stop listening. 1.100 + if (delegates.isEmpty()) { 1.101 + removeListener(); 1.102 + } 1.103 + } 1.104 +}