Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9d2f114 authored by Fred Quintana's avatar Fred Quintana
Browse files

change the sync framework and users to understand Account

parent 843bbb85
Loading
Loading
Loading
Loading
+73 −68
Original line number Diff line number Diff line
@@ -13092,6 +13092,23 @@
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="addOnAccountsUpdatedListener"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
</parameter>
<parameter name="handler" type="android.os.Handler">
</parameter>
<parameter name="updateImmediately" type="boolean">
</parameter>
</method>
<method name="blockingAddAccountExplicitly"
 return="boolean"
 abstract="false"
@@ -13636,6 +13653,19 @@
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
<method name="removeOnAccountsUpdatedListener"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
</parameter>
</method>
<method name="setAuthToken"
 return="android.accounts.Future1&lt;java.lang.Void&gt;"
 abstract="false"
@@ -13721,74 +13751,6 @@
</parameter>
</method>
</class>
<class name="AccountMonitor"
 extends="android.content.BroadcastReceiver"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="AccountMonitor"
 type="android.accounts.AccountMonitor"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="listener" type="android.accounts.AccountMonitorListener">
</parameter>
</constructor>
<method name="close"
 return="void"
 abstract="false"
 native="false"
 synchronized="true"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="onReceive"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="intent" type="android.content.Intent">
</parameter>
</method>
</class>
<interface name="AccountMonitorListener"
 abstract="true"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="onAccountsUpdated"
 return="void"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="currentAccounts" type="java.lang.String[]">
</parameter>
</method>
</interface>
<class name="AuthenticatorBindHelper"
 extends="java.lang.Object"
 abstract="false"
@@ -14704,6 +14666,27 @@
</parameter>
</constructor>
</class>
<interface name="OnAccountsUpdatedListener"
 abstract="true"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="onAccountsUpdated"
 return="void"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="accounts" type="android.accounts.Account[]">
</parameter>
</method>
</interface>
<class name="OperationCanceledException"
 extends="java.lang.Exception"
 abstract="false"
@@ -99012,6 +98995,17 @@
 visibility="public"
>
</field>
<field name="GROUP_SYNC_ACCOUNT_TYPE"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;group_sync_account_type&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="GROUP_SYNC_ID"
 type="java.lang.String"
 transient="false"
@@ -100954,6 +100948,17 @@
 visibility="public"
>
</field>
<field name="_SYNC_ACCOUNT_TYPE"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;_sync_account_type&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
</interface>
<class name="LiveFolders"
 extends="java.lang.Object"
+163 −10
Original line number Diff line number Diff line
@@ -19,11 +19,15 @@ package android.accounts;
import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.Parcelable;
import android.util.Config;
import android.util.Log;

import java.io.IOException;
import java.util.concurrent.Callable;
@@ -32,6 +36,10 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
import java.util.Map;

import com.google.android.collect.Maps;

/**
 * A class that helps with interactions with the AccountManagerService. It provides
@@ -48,6 +56,7 @@ public class AccountManager {

    private final Context mContext;
    private final IAccountManager mService;
    private final Handler mMainHandler;

    /**
     * @hide
@@ -55,6 +64,7 @@ public class AccountManager {
    public AccountManager(Context context, IAccountManager service) {
        mContext = context;
        mService = service;
        mMainHandler = new Handler(mContext.getMainLooper());
    }

    public static AccountManager get(Context context) {
@@ -454,24 +464,28 @@ public class AccountManager {

    private void postToHandler(Handler handler, final Future2Callback callback,
            final Future2 future) {
        if (handler == null) {
            handler = new Handler(mContext.getMainLooper());
        }
        final Handler innerHandler = handler;
        innerHandler.post(new Runnable() {
        handler = handler == null ? mMainHandler : handler;
        handler.post(new Runnable() {
            public void run() {
                callback.run(future);
            }
        });
    }

    private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
            final Account[] accounts) {
        handler = handler == null ? mMainHandler : handler;
        handler.post(new Runnable() {
            public void run() {
                listener.onAccountsUpdated(accounts);
            }
        });
    }

    private <V> void postToHandler(Handler handler, final Future1Callback<V> callback,
            final Future1<V> future) {
        if (handler == null) {
            handler = new Handler(mContext.getMainLooper());
        }
        final Handler innerHandler = handler;
        innerHandler.post(new Runnable() {
        handler = handler == null ? mMainHandler : handler;
        handler.post(new Runnable() {
            public void run() {
                callback.run(future);
            }
@@ -908,4 +922,143 @@ public class AccountManager {
        new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType,  features,
                activityForPrompting, addAccountOptions, loginOptions, callback, handler).start();
    }

    private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
            Maps.newHashMap();

    // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver
    // and its getAccounts() callback which are both invoked only on the main thread. As a
    // result we don't need to protect against concurrent accesses and any changes are guaranteed
    // to be visible when used. Basically, these two variables are thread-confined.
    private Future1<Account[]> mAccountsLookupFuture = null;
    private boolean mAccountLookupPending = false;

    /**
     * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
     * so that it can read the updated list of accounts and send them to the listener
     * in mAccountsUpdatedListeners.
     */
    private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
        public void onReceive(final Context context, final Intent intent) {
            if (mAccountsLookupFuture != null) {
                // an accounts lookup is already in progress,
                // don't bother starting another request
                mAccountLookupPending = true;
                return;
            }
            // initiate a read of the accounts
            mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() {
                public void run(Future1<Account[]> future) {
                    // clear the future so that future receives will try the lookup again
                    mAccountsLookupFuture = null;

                    // get the accounts array
                    Account[] accounts;
                    try {
                        accounts = future.getResult();
                    } catch (OperationCanceledException e) {
                        // this should never happen, but if it does pretend we got another
                        // accounts changed broadcast
                        if (Config.LOGD) {
                            Log.d(TAG, "the accounts lookup for listener notifications was "
                                    + "canceled, try again by simulating the receipt of "
                                    + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast");
                        }
                        onReceive(context, intent);
                        return;
                    }

                    // send the result to the listeners
                    synchronized (mAccountsUpdatedListeners) {
                        for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
                                mAccountsUpdatedListeners.entrySet()) {
                            Account[] accountsCopy = new Account[accounts.length];
                            // send the listeners a copy to make sure that one doesn't
                            // change what another sees
                            System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
                            postToHandler(entry.getValue(), entry.getKey(), accountsCopy);
                        }
                    }

                    // If mAccountLookupPending was set when the account lookup finished it
                    // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION
                    // intent because a lookup was already in progress. Now that we are done
                    // with this lookup and notification pretend that another intent
                    // was received by calling onReceive() directly.
                    if (mAccountLookupPending) {
                        mAccountLookupPending = false;
                        onReceive(context, intent);
                        return;
                    }
                }
            }, mMainHandler);
        }
    };

    /**
     * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
     * The listener is guaranteed to be invoked on the thread of the Handler that is passed
     * in or the main thread's Handler if handler is null.
     * @param listener the listener to add
     * @param handler the Handler whose thread will be used to invoke the listener. If null
     * the AccountManager context's main thread will be used.
     * @param updateImmediately if true then the listener will be invoked as a result of this
     * call.
     * @throws IllegalArgumentException if listener is null
     * @throws IllegalStateException if listener was already added
     */
    public void addOnAccountsUpdatedListener(final OnAccountsUpdatedListener listener,
            Handler handler, boolean updateImmediately) {
        if (listener == null) {
            throw new IllegalArgumentException("the listener is null");
        }
        synchronized (mAccountsUpdatedListeners) {
            if (mAccountsUpdatedListeners.containsKey(listener)) {
                throw new IllegalStateException("this listener is already added");
            }
            final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();

            mAccountsUpdatedListeners.put(listener, handler);

            if (wasEmpty) {
                // Register a broadcast receiver to monitor account changes
                IntentFilter intentFilter = new IntentFilter();
                intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
                mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
            }
        }

        if (updateImmediately) {
            getAccounts(new Future1Callback<Account[]>() {
                public void run(Future1<Account[]> future) {
                    try {
                        listener.onAccountsUpdated(future.getResult());
                    } catch (OperationCanceledException e) {
                        // ignore
                    }
                }
            }, handler);
        }
    }

    /**
     * Remove an {@link OnAccountsUpdatedListener} that was previously registered with
     * {@link #addOnAccountsUpdatedListener}.
     * @param listener the listener to remove
     * @throws IllegalArgumentException if listener is null
     * @throws IllegalStateException if listener was not already added
     */
    public void removeOnAccountsUpdatedListener(OnAccountsUpdatedListener listener) {
        if (listener == null) {
            throw new IllegalArgumentException("the listener is null");
        }
        synchronized (mAccountsUpdatedListeners) {
            if (mAccountsUpdatedListeners.remove(listener) == null) {
                throw new IllegalStateException("this listener was not previously added");
            }
            if (mAccountsUpdatedListeners.isEmpty()) {
                mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
            }
        }
    }
}
+0 −120
Original line number Diff line number Diff line
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.accounts;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.*;

/**
 * A helper class that calls back on the provided
 * AccountMonitorListener with the set of current accounts both when
 * it gets created and whenever the set changes. It does this by
 * binding to the AccountsService and registering to receive the
 * intent broadcast when the set of accounts is changed.  The
 * connection to the accounts service is only made when it needs to
 * fetch the current list of accounts (that is, when the
 * AccountMonitor is first created, and when the intent is received).
 */
public class AccountMonitor extends BroadcastReceiver {
    private static final String TAG = "AccountMonitor";

    private final Context mContext;
    private final AccountMonitorListener mListener;
    private boolean mClosed = false;

    private volatile Looper mServiceLooper;
    private volatile NotifierHandler mServiceHandler;

    /**
     * Initializes the AccountMonitor and initiates a bind to the
     * AccountsService to get the initial account list.  For 1.0,
     * the "list" is always a single account.
     *
     * @param context the context we are running in
     * @param listener the user to notify when the account set changes
     */
    public AccountMonitor(Context context, AccountMonitorListener listener) {
        if (listener == null) {
            throw new IllegalArgumentException("listener is null");
        }

        mContext = context;
        mListener = listener;

        // Register a broadcast receiver to monitor account changes
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);  // To recover from disk-full.
        mContext.registerReceiver(this, intentFilter);

        HandlerThread thread = new HandlerThread("AccountMonitorHandlerThread");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new NotifierHandler(mServiceLooper);

        mServiceHandler.sendEmptyMessage(0);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        notifyListener();
    }

    private Future1Callback<Account[]> mGetAccountsCallback = new Future1Callback<Account[]>() {
        public void run(Future1<Account[]> future) {
            try {
                Account[] accounts = future.getResult();
                String[] accountNames = new String[accounts.length];
                for (int i = 0; i < accounts.length; i++) {
                    accountNames[i] = accounts[i].mName;
                }
                mListener.onAccountsUpdated(accountNames);
            } catch (OperationCanceledException e) {
                // the request was canceled
            }
        }
    };

    private synchronized void notifyListener() {
        AccountManager.get(mContext).getAccounts(mGetAccountsCallback, null /* handler */);
    }

    /**
     * Unregisters the account receiver.  Consecutive calls to this
     * method are harmless, but also do nothing.  Once this call is
     * made no more notifications will occur.
     */
    public synchronized void close() {
        if (!mClosed) {
            mContext.unregisterReceiver(this);
            mClosed = true;
        }
    }

    private final class NotifierHandler extends Handler {
        public NotifierHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            notifyListener();
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -19,11 +19,11 @@ package android.accounts;
/**
 * An interface that contains the callback used by the AccountMonitor
 */
public interface AccountMonitorListener {
public interface OnAccountsUpdatedListener {
    /**
     * This invoked when the AccountMonitor starts up and whenever the account
     * set changes.
     * @param currentAccounts the current accounts
     * @param accounts the current accounts
     */
    void onAccountsUpdated(String[] currentAccounts);
    void onAccountsUpdated(Account[] accounts);
}
+46 −42

File changed.

Preview size limit exceeded, changes collapsed.

Loading