michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0:
michael@0: package org.mozilla.gecko.fxa.sync;
michael@0:
michael@0: import java.util.Map;
michael@0: import java.util.Map.Entry;
michael@0: import java.util.WeakHashMap;
michael@0:
michael@0: import org.mozilla.gecko.fxa.FirefoxAccounts;
michael@0: import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
michael@0:
michael@0: import android.content.ContentResolver;
michael@0: import android.content.SyncStatusObserver;
michael@0:
michael@0: /**
michael@0: * Abstract away some details of Android's SyncStatusObserver.
michael@0: *
michael@0: * Provides a simplified sync started/sync finished delegate.
michael@0: */
michael@0: public class FxAccountSyncStatusHelper implements SyncStatusObserver {
michael@0: @SuppressWarnings("unused")
michael@0: private static final String LOG_TAG = FxAccountSyncStatusHelper.class.getSimpleName();
michael@0:
michael@0: protected static FxAccountSyncStatusHelper sInstance = null;
michael@0:
michael@0: public synchronized static FxAccountSyncStatusHelper getInstance() {
michael@0: if (sInstance == null) {
michael@0: sInstance = new FxAccountSyncStatusHelper();
michael@0: }
michael@0: return sInstance;
michael@0: }
michael@0:
michael@0: // Used to unregister this as a listener.
michael@0: protected Object handle = null;
michael@0:
michael@0: // Maps delegates to whether their underlying Android account was syncing the
michael@0: // last time we observed a status change.
michael@0: protected Map delegates = new WeakHashMap();
michael@0:
michael@0: @Override
michael@0: public synchronized void onStatusChanged(int which) {
michael@0: for (Entry entry : delegates.entrySet()) {
michael@0: final FirefoxAccounts.SyncStatusListener delegate = entry.getKey();
michael@0: final AndroidFxAccount fxAccount = new AndroidFxAccount(delegate.getContext(), delegate.getAccount());
michael@0: final boolean active = fxAccount.isCurrentlySyncing();
michael@0: // Remember for later.
michael@0: boolean wasActiveLastTime = entry.getValue();
michael@0: // It's okay to update the value of an entry while iterating the entrySet.
michael@0: entry.setValue(active);
michael@0:
michael@0: if (active && !wasActiveLastTime) {
michael@0: // We've started a sync.
michael@0: delegate.onSyncStarted();
michael@0: }
michael@0: if (!active && wasActiveLastTime) {
michael@0: // We've finished a sync.
michael@0: delegate.onSyncFinished();
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: protected void addListener() {
michael@0: final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
michael@0: if (this.handle != null) {
michael@0: throw new IllegalStateException("Already registered this as an observer?");
michael@0: }
michael@0: this.handle = ContentResolver.addStatusChangeListener(mask, this);
michael@0: }
michael@0:
michael@0: protected void removeListener() {
michael@0: Object handle = this.handle;
michael@0: this.handle = null;
michael@0: if (handle != null) {
michael@0: ContentResolver.removeStatusChangeListener(handle);
michael@0: }
michael@0: }
michael@0:
michael@0: public synchronized void startObserving(FirefoxAccounts.SyncStatusListener delegate) {
michael@0: if (delegate == null) {
michael@0: throw new IllegalArgumentException("delegate must not be null");
michael@0: }
michael@0: if (delegates.containsKey(delegate)) {
michael@0: return;
michael@0: }
michael@0: // If we are the first delegate to the party, start listening.
michael@0: if (delegates.isEmpty()) {
michael@0: addListener();
michael@0: }
michael@0: delegates.put(delegate, Boolean.FALSE);
michael@0: }
michael@0:
michael@0: public synchronized void stopObserving(FirefoxAccounts.SyncStatusListener delegate) {
michael@0: delegates.remove(delegate);
michael@0: // If we are the last delegate leaving the party, stop listening.
michael@0: if (delegates.isEmpty()) {
michael@0: removeListener();
michael@0: }
michael@0: }
michael@0: }