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

Commit d004ee1b authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 497

* changes:
  change the sync framework and users to understand Account
parents bc2e33b5 d9d2f114
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