AccountManagerService.java revision 42c98ada113ae5b7c72ecb6d0de721ec1d0d3534
1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
20a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
21a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
22a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
23a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
24d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
25d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
267be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.PackageInfo;
277be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.ApplicationInfo;
283ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
29603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
30603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
31a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
32a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
33a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
35a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
40a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
41d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.Binder;
42d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.SystemProperties;
43603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.telephony.TelephonyManager;
44a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
45a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
46d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
4726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.PendingIntent;
4826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.NotificationManager;
4926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.Notification;
50d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.Manifest;
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
53a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
54a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
55a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
56a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.LinkedHashMap;
57d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
58d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
59d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
61603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport com.android.internal.telephony.TelephonyIntents;
6226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport com.android.internal.R;
63603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
64603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
65603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
66603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
67603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
68603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *    AccountManager accountManager =
70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
733ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
743ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        implements RegisteredServicesCacheListener<AuthenticatorDescription> {
763348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
7750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
7850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller    private static final String NO_BROADCAST_FLAG = "nobroadcast";
7950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
80603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
81603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
83603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
843348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final int DATABASE_VERSION = 4;
85603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
90603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_CONNECTED = 7;
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_DISCONNECTED = 8;
95603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AccountAuthenticatorCache mAuthenticatorCache;
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AuthenticatorBindHelper mBindHelper;
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final DatabaseHelper mOpenHelper;
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final SimWatcher mSimWatcher;
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
1051cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
114d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
115d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
116d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
117d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
118d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
120603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
1311cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
1321cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
1337be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
135d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
136d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
137d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
141d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
143a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
147d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            mCredentialsPermissionNotificationIds =
148d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
149d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
150d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Account, Integer>();
151d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
152d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
153d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
154d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final boolean isDebuggableMonkeyBuild =
15542c98ada113ae5b7c72ecb6d0de721ec1d0d3534Ying Wang            SystemProperties.getBoolean("ro.monkey", false);
15631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
1577be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1587be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
159f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
1607be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1617be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1627be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
163d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
164d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
165d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
166d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
167d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
168d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
169d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
170d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
171d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public class AuthTokenKey {
174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final Account mAccount;
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mAuthTokenType;
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private final int mHashCode;
177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public AuthTokenKey(Account account, String authTokenType) {
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccount = account;
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthTokenType = authTokenType;
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mHashCode = computeHashCode();
182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public boolean equals(Object o) {
185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (o == this) {
186603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!(o instanceof AuthTokenKey)) {
189603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            AuthTokenKey other = (AuthTokenKey)o;
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mAccount.equals(other.mAccount)) {
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return (mAuthTokenType == null)
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    ? other.mAuthTokenType == null
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    : mAuthTokenType.equals(other.mAuthTokenType);
198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private int computeHashCode() {
201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            int result = 17;
202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + mAccount.hashCode();
203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return result;
205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
206603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public int hashCode() {
208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mHashCode;
209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
212603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManagerService(Context context) {
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper = new DatabaseHelper(mContext);
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
2225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        mAuthenticatorCache.setListener(this, null /* Handler */);
223603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
224603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
225603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mSimWatcher = new SimWatcher(mContext);
227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
2283ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
2293ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana    public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
2313ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        boolean accountDeleted = false;
2323ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2333ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
2343ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
2355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                ACCOUNTS_TYPE + "=?", new String[]{desc.type}, null, null, null);
2363ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        try {
2373ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            while (cursor.moveToNext()) {
2383ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final long accountId = cursor.getLong(0);
2393ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountType = cursor.getString(1);
2403ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountName = cursor.getString(2);
2415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                Log.d(TAG, "deleting account " + accountName + " because type "
2425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                        + accountType + " no longer has a registered authenticator");
2435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
2445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                accountDeleted = true;
2453ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2463ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        } finally {
2473ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            cursor.close();
2483ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            if (accountDeleted) {
2493ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                sendAccountsChangedBroadcast();
2503ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2513ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        }
252603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
253603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
254a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
255d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
256d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
25726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
258603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
259ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
260603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
26126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
264603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
265ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
26631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
26731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
26831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
26931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
270ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
271ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
272ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
273ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
274ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
275ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
276ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
277ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
278ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
279ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
280ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
281ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
282ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
283ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
284a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
285d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
28626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
288ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
289ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
290ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
291ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
292ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
293ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
294ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
29531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
29631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
29731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
29831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
299ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
30086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
30186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                EXTRAS_ACCOUNTS_ID
30286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
30386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + EXTRAS_KEY + "=?",
30486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, key}, null, null, null);
305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
30686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
30786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
308603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
30986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
310603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
31186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
3159788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
31626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
31726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3189788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3199788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3209788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3219788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
32226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3239788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
324718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
325718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
32626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
32726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
32826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
32926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
33026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
331a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
332a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
333a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
334a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
33626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
337ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
339ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
341ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
342ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
344ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
346ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
348ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
350ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
351603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
352603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
353603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
355d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
356d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
35826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
359603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
360ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
361ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
362ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
363ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
367ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
369ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
37031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            if (account == null) {
37131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                return false;
37231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            }
37350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            boolean noBroadcast = false;
37450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (account.type.equals(GOOGLE_ACCOUNT_TYPE)) {
37550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // Look for the 'nobroadcast' flag and remove it since we don't want it to persist
37650c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // in the db.
37750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                noBroadcast = extras.getBoolean(NO_BROADCAST_FLAG, false);
37850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                extras.remove(NO_BROADCAST_FLAG);
37950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
38050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
381ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
382ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
383ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
386ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
388ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
392ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
393ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
395ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
396ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
397ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
400ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
404ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
40550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (!noBroadcast) {
40650c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                sendAccountsChangedBroadcast();
40750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
408ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
410ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
419603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
422ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
423d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
42426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
42526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
42726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
42826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
429a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
433ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
435ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
436ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
437ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
439ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
441ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
443ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
444ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
445ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
446ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
448ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
449f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
450f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
451f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
452ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
453ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
454ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
455ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
456ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
457ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
458f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
459ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
460ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
461ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
462ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
463ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
464ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
465ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
466ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
467ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
468ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
469ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
470ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
471ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
472ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
473ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
474ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
475ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
476ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
477a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
478d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
47926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
480603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
48126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
48226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
48326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
48426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
48526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
48626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
48726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
48826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
489603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
49026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
491603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
492603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
493603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
494603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
495ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
496ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
497ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
4983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
4993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
5003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
5013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
5023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
5033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
5043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
5053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
5063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
5073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
5083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
5093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
5103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
5113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
5123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
5133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
5143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
5163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
5173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
52231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
52331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
52431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
5256dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
526603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
527603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
528603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
5293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
5303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
5313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
5323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
5333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
5343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
5353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
5363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
5373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
5383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
5393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
5403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
541603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
542603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
543603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
544603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
545603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
546603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
547603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
549603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
550603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
55131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || authTokenType == null) {
55231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
55331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
554603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
55586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
55686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
55786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + AUTHTOKENS_TYPE + "=?",
55886bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, authTokenType},
55986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                null, null, null);
560603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
56186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
56286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
563603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
56486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
565603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
56686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
567603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
568603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
569603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
570a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
571d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
57226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
57326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
57526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
57626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
579603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
580a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
581d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
58226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
58326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5846dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
58526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
58626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
58726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
588603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
589603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
590a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
591d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
59226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
59326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5943ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
59526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
59626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
59726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
6003ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
60131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
60231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
60331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
6043ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        ContentValues values = new ContentValues();
6053ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        values.put(ACCOUNTS_PASSWORD, password);
6063ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
6073ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
6083ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{account.name, account.type});
6093ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
6103ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
6113ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
6123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
6133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
6143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
6153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
616a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
61826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
61926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6203ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
62126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
62226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
62326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
624603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
625603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
626a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
627d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
62826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
62931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
63031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
63131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
63250c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        if (account.type.equals(GOOGLE_ACCOUNT_TYPE) && key.equals("broadcast")) {
63350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            sendAccountsChangedBroadcast();
63450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            return;
63550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        }
636603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
637ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
638ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
639ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
640ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
641ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
642ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
643ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
64431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
64531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
64631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
647ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
648ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
649ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
650ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
651ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
652ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
653ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
654ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
655ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
656ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
657ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
658603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
659603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
660ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
661ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
662ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
663ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
664ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
66526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
666ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
667603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
668ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
669603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
670ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
671603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
672603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
673603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
675d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
680d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
681d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
682d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
683d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
684d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
685d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
686a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
687a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
688a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
689d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
690d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
691d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
69326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
69426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
695d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
696d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
699d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
70026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
701f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
702f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
703f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
704d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
705d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
706a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
707a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
708603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
709ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
71026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
71126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
71226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
71326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
71426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
71526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
71626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
71726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
718a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
71926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
720d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
721d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
722d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
723d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
724d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
725d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
726d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
72726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
728a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
72926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
73026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
731f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
732d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
733d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
734d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
735f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
736d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
737f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
738d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
739d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
740d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
741f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
74226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
743f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
744f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
74526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
746f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
74726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
74826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
74926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
7506dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                            saveAuthTokenToDatabase(new Account(name, type),
7516dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                                    authTokenType, authToken);
752a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
753603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
754f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
75526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
756d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
757f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
75826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
75926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
760a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
76126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
762a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
76326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
76426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
76526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
76626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
767603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
768603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
772d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
773d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
774d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
775d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
776d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
777d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
778d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
779ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
780ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
781ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
782ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
783ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
784ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
785d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
786ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
788d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
789d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
790d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
791d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
794d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
795d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
796ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
797d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
798ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
799d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
801d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
802d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
803d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
804d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
806ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
807d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
809d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
810d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
815d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
816d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
824d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
825d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
826d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
827d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
828d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
829d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
830d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
831d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
832d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
833d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
834d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
835d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
836d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
837d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
838d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
839d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
840d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
841d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
842d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
843d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
845d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
846d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
847d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
848d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
849d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
850d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
851d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
852d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
853a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
8543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
8553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
856a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
857d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
85826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
85926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
86026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
86126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
8623348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
8633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
86426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
865a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
86626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
86726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
8683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
8693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
8703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
8713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
8723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
87326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
87426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
87526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
87626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
87726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
878603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
879603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
880a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
881f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
882d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
88326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
88426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
885ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
88626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
887f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
88826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
89026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
89126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
89226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
89326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
89426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
89526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
89626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
897603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
898603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
899a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
900a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
901a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
902d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
90326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
90426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
905ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
90626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
90726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
90826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
90926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
91026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
91126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
91226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
91326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
91426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
91526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
91626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
91726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
91826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
91926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
920603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
921603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
922a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
923a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
924d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
92526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
92626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
92726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
92826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
92926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
93026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
93126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
93226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
93326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
93426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
93526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
93626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
93726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
93826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
939603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
940603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
9423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
9433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
9443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
9453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
9463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
9483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
9493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(response, type, false /* expectActivityLaunch */);
9503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
9543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
9553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
9563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
9583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
9603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
9633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
9643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
9653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
9693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
9703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
971f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
972a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
973603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
974603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
9763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
9773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
978f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
9793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
981f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
9823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
9833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
9853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
986a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
9873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
9893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
9903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
9913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
9923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
9933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
9943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
9953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
997f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
9983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
9993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
10003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
10013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
10023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
10033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
10043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
10053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
10103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
10113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
10123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1014ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1015ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
1016ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1017ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1018ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
1019ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
1020ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1021ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1022ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1023ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1024ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1025ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
10263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
1027d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
1028ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
10293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
10303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
1031f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "type is null");
10323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
10333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
10343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
10353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
10373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
10393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1040ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1041ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                getAccountsByType(type);
1042ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1043ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
10443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
10453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
10463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
10473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
10493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1050603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1051603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1052ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1053603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1054603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1055603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1056603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1057603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1058603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1059603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1060603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1061603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1062603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1063603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1064603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1065603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1066603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1067603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1068603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1069603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1070603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1071603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1072603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1073603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1074603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1075603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1076603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1077a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1078a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
1079603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1080603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1081a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1082a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1083a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
10843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1085a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1086a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1087a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1088603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1089603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1090603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1091a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
1092a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                boolean expectActivityLaunch) {
1093603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1094a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
10953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
1096603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1097603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1098a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1099a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1100a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1101a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1102a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1103a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1104a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1105a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1106a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1107a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1108a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1116a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1117a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1118a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1119a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1120a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1121a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1122a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1123a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1126a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1127a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1128a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1129a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1131a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1133a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1135603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1136603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1138a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1139a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1140603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1141a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1142a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1143a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1144a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1145a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1146a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1147a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1148a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1149a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1150a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1151a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1152a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1153a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1154603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1155603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1157a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1158a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1159a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mBindHelper.bind(mAccountType, this)) {
1161a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1162f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mBindHelper.unbind(this);
1170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onConnected(IBinder service) {
1183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1184a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1185a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1186a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1187f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1188a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1189a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void run() throws RemoteException;
1193a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onDisconnected() {
1195a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1196a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1198f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1199a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1204a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1206f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1207a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1211a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1212a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1213f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1214f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1215f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1216d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1217d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1218d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1219d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1221a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1222a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1223f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1224a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1226a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1227603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1228603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1231f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1232a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1233a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
1234a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1235a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1236603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1238a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1241603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1243603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1247603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1248603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1249603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1250a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1251a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1252a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1253603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1254a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1255a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1256a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1257a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1260a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1261a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1262a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1263a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1264a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1265a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1266a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1267a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1268a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1269a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1271603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1273603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1274603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1275603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1276603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1277603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
12783348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1280603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mBindHelper.handleMessage(msg)) {
1281603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return;
1282603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1284603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1285603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1290603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1295603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1296603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(context, DATABASE_NAME, null, DATABASE_VERSION);
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1301603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1302603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1304603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1306603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1307603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1308603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1309603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1310603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1315603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1316d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1317d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1318603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1319603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1320603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1321603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1322603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1323603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1324603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1325603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1326603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1327603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1329d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1330d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1331d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1332d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1333a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1334a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1335a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1336a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1337a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1338a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1339a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1340d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1341d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1342a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1345d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1346d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1347d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1348d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1349d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1350d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1351d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1352d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1354603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1356a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1358a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1359d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1360d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1361d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1362d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1363d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1364d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1365d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1366d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1367d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1368a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1369a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
13703348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
13713348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
13723348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
13733348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
13743348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
13753348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1376603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1399603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1400603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
14143348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1419603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
1423603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String imsi = ((TelephonyManager) context.getSystemService(
1424603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Context.TELEPHONY_SERVICE)).getSubscriberId();
1425603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1426603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1427603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1428603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1429603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14335b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
143427844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
143527844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1438603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1439603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1440603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
14413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1442603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1447603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1451603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1452603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1453603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1454a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14551cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
14561cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
14571cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
14581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
14591cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
14601cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
14611cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
14621cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
14631cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
14641cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
14651cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
14661cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
1467a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1468a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
14691cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
14701cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
1471a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14721cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
14731cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
14741cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
14751cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (isCheckinRequest) {
14761cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            // This is a checkin request. *Only* upload the account types and the count of each.
14771cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1478a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14791cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
14801cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    null, null, ACCOUNTS_TYPE, null, null);
14811cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            try {
14821cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                while (cursor.moveToNext()) {
14831cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    // print type,count
14841cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
14851cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14861cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            } finally {
14871cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (cursor != null) {
14881cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    cursor.close();
14891cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14901cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
14911cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        } else {
14921cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            synchronized (mSessions) {
14931cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                final long now = SystemClock.elapsedRealtime();
14941cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                fout.println("AccountManagerService: " + mSessions.size() + " sessions");
14951cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                for (Session session : mSessions.values()) {
14961cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println("  " + session.toDebugString(now));
14971cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14981cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
14991cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
15001cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            fout.println();
15011cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            mAuthenticatorCache.dump(fd, fout, args);
15021cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
1503a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1504a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1505d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
150626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
150726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
150826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
150926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
151026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1511a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1512d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1513d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1514d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1515d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1516d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
151733f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
151833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1519d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1520d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
152133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
152233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
152333f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
152433f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1525d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1526d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1527d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
152833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        .notify(notificationId, n);
1529d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
153026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
153126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
153226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1533a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1534a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1535d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
153626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
153726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
153826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1539d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
154026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
154126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
154226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1543a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1544d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1545d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkBinderPermission(String permission) {
1546d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1547d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (mContext.checkCallingOrSelfPermission(permission) !=
1548d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PackageManager.PERMISSION_GRANTED) {
1549d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " lacks " + permission;
1550d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1551d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1552d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1553d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1554d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " has " + permission);
1555d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1556d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1557d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
15587be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
15597be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
15607be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
15617be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
15627be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
15637be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
15647be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
15657be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
15667be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
15677be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
15687be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
15697be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
15707be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
15717be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
15727be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
15737be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1574d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
157531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
157631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
157731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
157831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasExplicitlyGrantedPermission(account, authTokenType);
1579d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1580d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1581d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1582d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1583d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1584d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
15857be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
1586d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1587d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1588d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1589d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1590d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1591d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1592ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1593ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1594ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1595d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1596d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1597d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1598d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1599d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1600d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1601d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1603d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1604d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1605d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1606ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1607d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1608d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1609d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1610d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1611d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1612d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, "no credentials permission for usage of " + account + ", "
1613d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1614d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1615d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1616d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1618d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1619d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1620d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1621d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
162231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
1623d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1624d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1625d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1626d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1627d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1628d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1629d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1630d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1631d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1632d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1633d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1634d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1635d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1636d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1637d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1638d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1639d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1640d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1641d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1642d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1643d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1644d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1645d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1646d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1647d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1648d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1649d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1650d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1651d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1652d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
165331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null  || authTokenType == null) {
165431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
165531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1656d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1657d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1658d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1659d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1660d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1661d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1662d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1663d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1664d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1665d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1666d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1667d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1668d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1670d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1671d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1672d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1673d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1675d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1680d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1681d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1682d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
168331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null  || authTokenType == null) {
168431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
168531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1686d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1687d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1688d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1689d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1690d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1691d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1693d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1694d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1695d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1696d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1699d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1700d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1701d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1702d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1703603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1704