AccountManagerService.java revision f7ae77cd67f1a3993b8e56c1af4720a7adf4e69d
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
753ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        implements RegisteredServicesCacheListener {
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 =
155d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            SystemProperties.getBoolean("ro.monkey", false)
156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    && SystemProperties.getBoolean("ro.debuggable", false);
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);
2223ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mAuthenticatorCache.setListener(this);
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        onRegisteredServicesCacheChanged();
2303ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
2313ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2323ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    public void onRegisteredServicesCacheChanged() {
2333ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        boolean accountDeleted = false;
2343ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2353ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
2363ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
2373ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                null, null, null, null, null);
2383ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        try {
2393ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            while (cursor.moveToNext()) {
2403ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final long accountId = cursor.getLong(0);
2413ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountType = cursor.getString(1);
2423ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountName = cursor.getString(2);
2433ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                if (mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(accountType))
2443ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                        == null) {
2453ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    Log.d(TAG, "deleting account " + accountName + " because type "
2463ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                            + accountType + " no longer has a registered authenticator");
2473ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
2483ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    accountDeleted= true;
2493ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                }
2503ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2513ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        } finally {
2523ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            cursor.close();
2533ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            if (accountDeleted) {
2543ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                sendAccountsChangedBroadcast();
2553ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2563ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        }
257603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
258603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
260d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
261d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
26226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
264ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
265603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
26626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
270ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
271ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
272ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
273ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
274ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
275ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
276ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
277ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
278ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
279ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
280ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
281ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
282ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
283ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
284ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
285a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
28726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
289ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
290ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
291ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
292ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
293ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
294ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
295ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
296ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
29786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
29886bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                EXTRAS_ACCOUNTS_ID
29986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
30086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + EXTRAS_KEY + "=?",
30186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, key}, null, null, null);
302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
30386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
30486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
30686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
307603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
30886bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
309603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
310603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
3129788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
31326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
31426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3159788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3169788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3179788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3189788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
31926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3209788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
321718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
322718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
32326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
32426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
32526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
32626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
32726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
330a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
331a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
332ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
33326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
334ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
336ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
337ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
339ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
341ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
342ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
347ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
350603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
352d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
354603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
35526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
356603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
357ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
358ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
359ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
360ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
361ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
362ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
363ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
36750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            boolean noBroadcast = false;
36850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (account.type.equals(GOOGLE_ACCOUNT_TYPE)) {
36950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // Look for the 'nobroadcast' flag and remove it since we don't want it to persist
37050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // in the db.
37150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                noBroadcast = extras.getBoolean(NO_BROADCAST_FLAG, false);
37250c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                extras.remove(NO_BROADCAST_FLAG);
37350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
37450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
379ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
380ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
381ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
382ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
383ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
386ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
388ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
392ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
393ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
39950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (!noBroadcast) {
40050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                sendAccountsChangedBroadcast();
40150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
402ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
404ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
417d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
41826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
41926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
42126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
42226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
423a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
424603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
425603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
428ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
429ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
430ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
431ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
433ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
435ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
436ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
437ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
439ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
441ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
443f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
444f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
445f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
446ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
448ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
449ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
450ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
451ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
452f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
453ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
454ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
455ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
456ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
457ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
458ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
459ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
460ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
461ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
462ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
463ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
464ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
465ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
466ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
467ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
468ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
469ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
470ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
471a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
472d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
47326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
474603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
47526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
47626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
47726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
47826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
47926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
48026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
48126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
48226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
483603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
48426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
485603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
486603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
487603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
488603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
489ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
490ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
491ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
4923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
4933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
4943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
4953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
4963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
4973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
4983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
4993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
5003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
5013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
5023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
5033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
5043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
5053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
5063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
5073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
5083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
509603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
5103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
5113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
512603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
513603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
514603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
5166dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
517603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
5203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
5213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
5223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
5233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
5243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
5253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
5263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
5273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
5283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
5293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
5303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
5313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
532603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
533603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
534603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
535603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
536603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
537603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
538603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
539603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
540603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
541603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
542603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
54386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
54486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
54586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + AUTHTOKENS_TYPE + "=?",
54686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, authTokenType},
54786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                null, null, null);
548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
54986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
55086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
551603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
55286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
553603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
55486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
555603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
556603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
557603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
558a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
559d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
56026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
56126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
56326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
56426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
565603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
566603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
567603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
568a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
569d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
57026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
57126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5726dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
57326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
57426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
57526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
576603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
578a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
579d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
58026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
58126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5823ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
58326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
58426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
58526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
586603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
587603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
5883ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
5893ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        ContentValues values = new ContentValues();
5903ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        values.put(ACCOUNTS_PASSWORD, password);
5913ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
5923ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
5933ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{account.name, account.type});
5943ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
5953ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
5963ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
5973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
5983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
5993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
6003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
601a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
60326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
60426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6053ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
60626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
60726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
60826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
609603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
611ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void sendResult(IAccountManagerResponse response, Bundle bundle) {
612ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (response != null) {
613ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
614ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                response.onResult(bundle);
615ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
616ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // if the caller is dead then there is no one to care about remote
617ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // exceptions
618ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
619ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Log.v(TAG, "failure while notifying response", e);
620ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
621ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
622ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
623ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
624ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
625a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
626d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
62726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
62850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        if (account.type.equals(GOOGLE_ACCOUNT_TYPE) && key.equals("broadcast")) {
62950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            sendAccountsChangedBroadcast();
63050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            return;
63150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        }
632603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
633ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
634ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
635ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
636ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
637ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
638ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
639ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
640ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
641ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
642ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
643ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
644ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
645ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
646ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
647ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
648ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
649ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
650ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
652603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
653ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
654ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
655ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
656ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
657ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
65826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
659ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
660603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
661ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
662603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
663ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
664603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
665603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
666603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
667d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
668d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
670d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
671d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
672d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
673d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
675d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
679a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
680a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
681a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
682d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
683d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
684d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
685d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
68626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
688d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
689d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
690d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
691d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
69326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
694f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
695f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
696f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
699a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
700a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
701603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
702ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
70326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
70426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
70526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
70626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
70726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
70826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
70926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
71026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
711a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
71226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
713d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
714d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
715d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
716d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
717d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
718d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
719d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
72026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
721a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
72226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
72326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
724f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
725d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
726d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
727d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
728f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
729d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
730f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
731d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
732d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
733d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
734f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
73526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
736f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
737f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
73826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
739f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
74026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
74126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
74226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
7436dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                            saveAuthTokenToDatabase(new Account(name, type),
7446dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                                    authTokenType, authToken);
745a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
746603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
747f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
74826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
749d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
750f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
75126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
75226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
753a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
75426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
755a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
75626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
75726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
75826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
75926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
760603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
761603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
762d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
765d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
766d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
767d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
768d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
772ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
773ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
774ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
775ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
776ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
777ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
778d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
779ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
780d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
781d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
782d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
784d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
785d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
786d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
788d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
789ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
790d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
791ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
794d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
795d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
796d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
797d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
798d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
799ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
801d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
802d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
803d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
804d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
806d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
807d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
809d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
810d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
815d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
816d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
824d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
825d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
826d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
827d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
828d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
829d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
830d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
831d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
832d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
833d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
834d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
835d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
836d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
837d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
838d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
839d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
840d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
841d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
842d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
843d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
845d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
846a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
8473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
8483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
849a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
850d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
85126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
85226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
85326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
85426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
8553348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
8563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
85726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
858a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
85926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
86026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
8613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
8623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
8633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
8643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
8653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
86626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
86726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
86826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
86926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
87026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
871603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
872603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
873a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
874f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
875d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
87626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
87726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
878ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
87926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
880f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
88126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
88326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
88426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
88526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
88726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
88826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
88926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
890603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
891603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
892a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
893a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
894a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
895d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
89626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
89726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
898ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
89926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
90026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
90126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
90226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
90326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
90426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
90526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
90626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
90726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
90826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
90926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
91026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
91126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
91226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
913603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
914603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
915a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
916a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
917d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
91826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
91926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
92026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
92126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
92226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
92326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
92426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
92526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
92626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
92726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
92826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
92926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
93026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
93126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
932603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
933603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
9353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
9363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
9373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
9383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
9393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
9413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
9423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(response, type, false /* expectActivityLaunch */);
9433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
9443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
9473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
9483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
9493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
9503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
9533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
9563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
9583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
9623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
9633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
964f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
965a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
966603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
967603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
9693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
9703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
971f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
9723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
974f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
9753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
9763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
9783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
979a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
9803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
9823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
9833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
9843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
9853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
9863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
9873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
9883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
990f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
9913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
9923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
9933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
9943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
9953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
9963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
9983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
10033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
10043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
10053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1007ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1008ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
1009ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1010ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1011ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
1012ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
1013ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1014ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1015ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1016ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1017ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1018ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
10193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
1020d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
1021ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
10223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
10233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
1024f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "type is null");
10253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
10263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
10273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
10283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
10303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
10323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1033ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1034ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                getAccountsByType(type);
1035ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1036ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
10373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
10383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
10393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
10403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
10423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1043603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1044603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1045ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1046603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1047603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1048603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1049603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1050603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1051603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1052603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1053603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1054603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1055603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1056603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1057603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1058603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1059603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1060603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1061603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1062603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1063603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1064603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1065603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1066603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1067603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1068603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1069603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1070a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1071a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
1072603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1073603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1074a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1075a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1076a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
10773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1078a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1079a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1080a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1081603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1082603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1083603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1084a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
1085a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                boolean expectActivityLaunch) {
1086603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1087a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
10883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
1089603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1090603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1091a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1092a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1093a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1094a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1095a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1096a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1097a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1098a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1099a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1100a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1101a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1104a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1109a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1110a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1112a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1113a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1114a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1115a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1116a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1117a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1118a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1119a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1120a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1121a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1122a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1123a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1126a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1127a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1131a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1138a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1139a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1140a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1141a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1142a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1143a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1144a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1145a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1146a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1147603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1148603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1149603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1150a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1151a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1152a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1153603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mBindHelper.bind(mAccountType, this)) {
1154a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1155f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1157603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1158603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1162603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mBindHelper.unbind(this);
1163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onConnected(IBinder service) {
1176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1177a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1178a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1179a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1180f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1181a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1182a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1185a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void run() throws RemoteException;
1186a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onDisconnected() {
1188a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1189a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1191f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1197a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1199f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1200a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1204a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1205a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1206f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1207f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1208f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1209d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1210d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1211d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1212d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1214a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1215a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1216f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1217a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1218a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1219a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1222603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1223a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1224f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1226a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
1227a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1228a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1232a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1233a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1234603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1235603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1236603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1237603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1238a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1240603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1241603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1243a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1244a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1246603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1248a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1249a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1250a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1251a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1252a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1253a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1254a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1255a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1256a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1257a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1260a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1261a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1262a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1264603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1265603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
12713348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1273603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mBindHelper.handleMessage(msg)) {
1274603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return;
1275603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1276603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1277603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1278603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1280603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1281603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1282603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1284603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1285603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1290603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(context, DATABASE_NAME, null, DATABASE_VERSION);
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1295603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1296603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1301603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1302603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1304603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1306603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1307603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1308603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1309d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1310d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1315603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1316603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1318603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1319603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1320603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1321a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1322d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1323d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1324d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1325d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1326a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1327a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1330a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1331a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1332a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1333d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1334d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1335a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1336603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1338d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1339d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1340d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1341d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1342d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1343d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1344d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1345d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1346d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1349a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1350603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1352d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1354d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1355d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1356d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1357d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1358d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1359d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1360d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1361a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1362a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
13633348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
13643348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
13653348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
13663348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
13673348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
13683348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1370603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1371603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1375603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1376603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1399603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1400603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
14073348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
1416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String imsi = ((TelephonyManager) context.getSystemService(
1417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Context.TELEPHONY_SERVICE)).getSubscriberId();
1418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1419603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1423603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1424603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1425603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14265b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
142727844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
142827844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1429603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1433603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
14343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1435603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1438603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1439603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1440603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1442603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1447a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14481cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
14491cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
14501cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
14511cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
14521cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
14531cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
14541cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
14551cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
14561cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
14571cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
14581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
14591cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
1460a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1461a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
14621cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
14631cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
1464a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14651cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
14661cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
14671cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
14681cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (isCheckinRequest) {
14691cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            // This is a checkin request. *Only* upload the account types and the count of each.
14701cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1471a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
14721cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
14731cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    null, null, ACCOUNTS_TYPE, null, null);
14741cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            try {
14751cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                while (cursor.moveToNext()) {
14761cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    // print type,count
14771cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
14781cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14791cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            } finally {
14801cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (cursor != null) {
14811cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    cursor.close();
14821cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14831cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
14841cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        } else {
14851cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            synchronized (mSessions) {
14861cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                final long now = SystemClock.elapsedRealtime();
14871cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                fout.println("AccountManagerService: " + mSessions.size() + " sessions");
14881cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                for (Session session : mSessions.values()) {
14891cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println("  " + session.toDebugString(now));
14901cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
14911cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
14921cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
14931cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            fout.println();
14941cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            mAuthenticatorCache.dump(fd, fout, args);
14951cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
1496a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1497a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1498d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
149926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
150026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
150126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
150226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
150326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1504a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1505d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1506d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1507d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1508d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1509d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
151033f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
151133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1512d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1513d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
151433f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
151533f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
151633f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
151733f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1518d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1519d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1520d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
152133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        .notify(notificationId, n);
1522d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
152326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
152426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
152526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1526a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1527a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1528d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
152926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
153026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
153126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1532d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
153326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
153426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
153526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1536a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1537d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1538d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkBinderPermission(String permission) {
1539d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1540d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (mContext.checkCallingOrSelfPermission(permission) !=
1541d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PackageManager.PERMISSION_GRANTED) {
1542d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " lacks " + permission;
1543d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1544d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1545d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1546d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1547d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " has " + permission);
1548d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1549d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1550d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
15517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
15527be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
15537be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
15547be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
15557be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
15567be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
15577be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
15587be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
15597be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
15607be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
15617be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
15627be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
15637be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
15647be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
15657be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
15667be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1567d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1568ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
1569d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
1570d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1571d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1572d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1573d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1574d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1575d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
15767be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
1577d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1578d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1579d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1580d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1581d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1582d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1583ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1584ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1585ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1586d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1587d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1588d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1589d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1590d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1591d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1592d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1593d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1594d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1595d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1596d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1597ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1598d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1599d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1600d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1601d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1603d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, "no credentials permission for usage of " + account + ", "
1604d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1605d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1606d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1607d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1608d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1609d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1610d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1611d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1612d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1613ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (!hasAuthenticatorUid(account.type, uid)) {
1614d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1615d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1616d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1618d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1619d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1620d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1621d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1622d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1623d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1624d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1625d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1626d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1627d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1628d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1629d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1630d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1631d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1632d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1633d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1634d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1635d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1636d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1637d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1638d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1639d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1640d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1641d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1642d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1643d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
1644d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1645d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1646d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1647d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1648d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1649d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1650d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1651d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1652d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1653d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1654d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1655d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1656d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1657d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1658d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1659d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1660d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1661d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1662d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1663d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1664d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1665d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1666d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1667d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1668d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1670d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
1671d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1672d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1673d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1675d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1680d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1681d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1682d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1683d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1684d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1685d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1686d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1687d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1688603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1689