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
19885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.Manifest;
20885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.Notification;
21885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.NotificationManager;
22885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.PendingIntent;
23a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
24885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.ComponentName;
25a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
26a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
27a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
28a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
29b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintanaimport android.content.ServiceConnection;
30885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.ApplicationInfo;
31885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.PackageInfo;
32d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
33d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
343ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
35603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
36603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
39885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.os.Binder;
40a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
41a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport android.os.Environment;
42a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
43a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
44a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
45a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
46a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
47a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
48885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.os.ServiceManager;
49a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
50d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.SystemProperties;
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.telephony.TelephonyManager;
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
53a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
54d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
55603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
56a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport java.io.File;
57a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
58a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
59a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
60a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
61a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.LinkedHashMap;
62d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
63d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
64d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
65603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
6626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport com.android.internal.R;
67885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport com.android.internal.telephony.ITelephony;
68885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport com.android.internal.telephony.TelephonyIntents;
69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
71603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
73603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *    AccountManager accountManager =
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
78603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
793ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
803ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        implements RegisteredServicesCacheListener<AuthenticatorDescription> {
823348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
8350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
8450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller    private static final String NO_BROADCAST_FLAG = "nobroadcast";
8550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
903348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final int DATABASE_VERSION = 4;
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
95603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AccountAuthenticatorCache mAuthenticatorCache;
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final DatabaseHelper mOpenHelper;
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final SimWatcher mSimWatcher;
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
1081cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
117d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
118d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
119d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
120d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
121d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
132603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
1341cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
1351cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
1367be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
141d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
146a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
147d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
148d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
149d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
150d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            mCredentialsPermissionNotificationIds =
151d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
152d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
153d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Account, Integer>();
154d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
155d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
157d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final boolean isDebuggableMonkeyBuild =
15842c98ada113ae5b7c72ecb6d0de721ec1d0d3534Ying Wang            SystemProperties.getBoolean("ro.monkey", false);
15931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
1607be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1617be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
162f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
1637be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1647be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1657be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
166d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
167d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
168d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
169d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
170d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
171d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
172d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
173d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
174d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public class AuthTokenKey {
177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final Account mAccount;
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mAuthTokenType;
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private final int mHashCode;
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public AuthTokenKey(Account account, String authTokenType) {
182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccount = account;
183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthTokenType = authTokenType;
184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mHashCode = computeHashCode();
185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
186603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public boolean equals(Object o) {
188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (o == this) {
189603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!(o instanceof AuthTokenKey)) {
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            AuthTokenKey other = (AuthTokenKey)o;
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mAccount.equals(other.mAccount)) {
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return (mAuthTokenType == null)
199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    ? other.mAuthTokenType == null
200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    : mAuthTokenType.equals(other.mAuthTokenType);
201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private int computeHashCode() {
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            int result = 17;
205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + mAccount.hashCode();
206603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return result;
208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public int hashCode() {
211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mHashCode;
212603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManagerService(Context context) {
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper = new DatabaseHelper(mContext);
219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
222603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
223603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
224603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
2255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        mAuthenticatorCache.setListener(this, null /* Handler */);
226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
227885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker        mSimWatcher = new SimWatcher(mContext);
228d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
229afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
230afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        validateAccounts();
231afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana    }
232afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
233afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana    private void validateAccounts() {
234afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        boolean accountDeleted = false;
235afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
236afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
237afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
238afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                null, null, null, null, null);
239afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        try {
240afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            while (cursor.moveToNext()) {
241afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                final long accountId = cursor.getLong(0);
242afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                final String accountType = cursor.getString(1);
243afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                final String accountName = cursor.getString(2);
244afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                if (mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(accountType))
245afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                        == null) {
246afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                    Log.d(TAG, "deleting account " + accountName + " because type "
247afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                            + accountType + " no longer has a registered authenticator");
248afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                    db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
249afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                    accountDeleted = true;
250afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                }
251afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
252afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        } finally {
253afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            cursor.close();
254afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            if (accountDeleted) {
255afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                sendAccountsChangedBroadcast();
256afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
257afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        }
2583ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
2593ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana    public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
2613ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        boolean accountDeleted = false;
2623ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2633ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
2643ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
2655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                ACCOUNTS_TYPE + "=?", new String[]{desc.type}, null, null, null);
2663ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        try {
2673ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            while (cursor.moveToNext()) {
2683ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final long accountId = cursor.getLong(0);
2693ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountType = cursor.getString(1);
2703ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountName = cursor.getString(2);
2715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                Log.d(TAG, "deleting account " + accountName + " because type "
2725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                        + accountType + " no longer has a registered authenticator");
2735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
2745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana                accountDeleted = true;
2753ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2763ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        } finally {
2773ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            cursor.close();
2783ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            if (accountDeleted) {
2793ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                sendAccountsChangedBroadcast();
2803ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2813ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        }
282603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
284a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
285382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
287d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
28826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
290ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
29226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
295603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
296ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
29731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
29831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
29931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
30031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
301ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
303ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
304ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
306ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
309ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
311ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
312ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
313ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
314ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
315a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
316382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
317382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
318d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
31926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
320603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
322ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
323ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
324ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
325ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
326ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
32831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
32931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
33031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
33131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
332ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
33386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
33486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                EXTRAS_ACCOUNTS_ID
33586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
33686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + EXTRAS_KEY + "=?",
33786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, key}, null, null, null);
338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
33986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
34086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
341603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
34286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
34486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
345603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
3489788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
34926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
35026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3519788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3529788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3539788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3549788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
35526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3569788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
357718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
358718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
35926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
36026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
36126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
36226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
36326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
364a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
365a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
366a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
367a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
36926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
370ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
371ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
372ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
373ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
374ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
379ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
381ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
383ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
387a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
388382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
389d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
390d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
39226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
395ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
396ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
397ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
400ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
401ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
402ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
403ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
40431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            if (account == null) {
40531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                return false;
40631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            }
40750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            boolean noBroadcast = false;
40850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (account.type.equals(GOOGLE_ACCOUNT_TYPE)) {
40950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // Look for the 'nobroadcast' flag and remove it since we don't want it to persist
41050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // in the db.
41150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                noBroadcast = extras.getBoolean(NO_BROADCAST_FLAG, false);
41250c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                extras.remove(NO_BROADCAST_FLAG);
41350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
41450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
415ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
417ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
421ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
422ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
423ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
424ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
425ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
428ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
429ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
430ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
431ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
433ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
435603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
43950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (!noBroadcast) {
44050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                sendAccountsChangedBroadcast();
44150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
444ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
447603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
451603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
452603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
453603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
454603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
455603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
4563084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public void hasFeatures(IAccountManagerResponse response,
457bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            Account account, String[] features) {
458382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
459382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
460382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (features == null) throw new IllegalArgumentException("features is null");
461bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        checkReadAccountsPermission();
462bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        long identityToken = clearCallingIdentity();
463bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        try {
464bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            new TestFeaturesSession(response, account, features).bind();
465bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        } finally {
466bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            restoreCallingIdentity(identityToken);
467bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
468bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
469bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
470bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    private class TestFeaturesSession extends Session {
471bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final String[] mFeatures;
472bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final Account mAccount;
473bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
474bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public TestFeaturesSession(IAccountManagerResponse response,
475bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                Account account, String[] features) {
4768570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, account.type, false /* expectActivityLaunch */,
4778570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
478bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mFeatures = features;
479bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mAccount = account;
480bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
481bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
482bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void run() throws RemoteException {
483bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            try {
484bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                mAuthenticator.hasFeatures(this, mAccount, mFeatures);
485bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            } catch (RemoteException e) {
486bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
487bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
488bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
489bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
490bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void onResult(Bundle result) {
491bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
492bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            if (response != null) {
493bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                try {
494bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (result == null) {
495bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
496bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        return;
497bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
498bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    final Bundle newResult = new Bundle();
499bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
500bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
501bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    response.onResult(newResult);
502bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                } catch (RemoteException e) {
503bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
504bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
505bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
506bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
507bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
508bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
509bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
510bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
511bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        protected String toDebugString(long now) {
5123084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana            return super.toDebugString(now) + ", hasFeatures"
513bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + mAccount
514bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
515bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
516bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
517307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
518ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
519382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
520382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
521d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
52226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
52326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
524ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
52526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
52626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
527a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
528603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
529603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
530ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
531ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
532ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
5338570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, account.type, false /* expectActivityLaunch */,
5348570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
536ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
537ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
538ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
543ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
544ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
545ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
546ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
547ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
548f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
549f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
550f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
551ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
552ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
553ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
554ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
555ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
556ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
557f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
558ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
559ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
560ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
561ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
562ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
563ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
564ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
565ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
567ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
568ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
569ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
570ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
571ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
572ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
573ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
574ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
575ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
576a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
577382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
578382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authToken == null) throw new IllegalArgumentException("authToken is null");
579b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkManageAccountsOrUseCredentialsPermissions();
58026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
581603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
58226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
58326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
58426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
58526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
58626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
58726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
58826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
58926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
590603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
59126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
592603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
593603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
594603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
595603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
596ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
597ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
598ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
5993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
6003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
6013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
6023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
6033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
6043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
6053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
6063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
6073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
6083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
6093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
6103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
6113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
6123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
6133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
6143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
6153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
616603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
6173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
6183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
619603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
620603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
621603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
622603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
62331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
62431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
62531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
6266dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
627603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
628603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
6303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
6313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
6323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
6333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
6343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
6353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
6363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
6373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
6383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
6393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
6403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
6413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
642603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
643603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
644603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
645603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
646603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
647603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
648603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
649603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
650603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
65231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || authTokenType == null) {
65331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
65431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
655603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
65686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
65786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
65886bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + AUTHTOKENS_TYPE + "=?",
65986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, authTokenType},
66086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                null, null, null);
661603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
66286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
66386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
664603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
66586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
666603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
66786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
668603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
669603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
670603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
671a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
672382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
673382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
67526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
67626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
67826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
67926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
680603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
681603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
682603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
683a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
684382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
685382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
686d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
68826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6896dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
69026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
69126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
69226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
693603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
694603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
695a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
696382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
69826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
69926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
7003ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
70126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
70226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
70326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
704603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
705603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
7063ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
70731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
70831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
70931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
710d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
711d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        db.beginTransaction();
712d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        try {
713d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            final ContentValues values = new ContentValues();
714d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
715d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            final long accountId = getAccountId(db, account);
716d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            if (accountId >= 0) {
717d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                final String[] argsAccountId = {String.valueOf(accountId)};
718d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
719d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
720d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.setTransactionSuccessful();
721d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            }
722d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        } finally {
723d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            db.endTransaction();
724d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        }
7253ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
7263ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
7273ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
7283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
7293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
7303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
7313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
732a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
733382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
734d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
73526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
73626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
7373ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
73826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
73926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
74026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
741603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
742603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
743a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
744382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
745382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
746d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
74726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
74831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
74931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
75031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
75150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        if (account.type.equals(GOOGLE_ACCOUNT_TYPE) && key.equals("broadcast")) {
75250c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            sendAccountsChangedBroadcast();
75350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            return;
75450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        }
755603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
756ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
757ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
758ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
759ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
760ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
761ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
762ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
76331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
76431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
76531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
766ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
767ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
768ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
769ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
770ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
771ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
772ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
773ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
774ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
775ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
776ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
777603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
778603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
779ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
780ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
781ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
782ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
783ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
78426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
785ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
786603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
787ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
788603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
789ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
790603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
791603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
792603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
794d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
795d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
796d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
797d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
798d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
799d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
801d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
802d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
803d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
804d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
805a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
806a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
807a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
808382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
809382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
810382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
81526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
81626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
82226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
823f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
824f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
825f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
826d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
827d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
828a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
829a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
830603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
8318570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
8328570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    false /* stripAuthTokenFromResult */) {
83326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
83426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
83526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
83626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
83726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
83826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
83926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
84026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
841a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
84226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
843d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
845d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
846d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
847d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
848d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
849d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
85026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
851a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
85226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
85326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
854f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
855d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
856d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
857d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
858f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
859d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
860f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
861d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
862d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
863d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
864f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
86526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
866f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
867f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
86826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
869f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
87026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
87126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
87226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
8736dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                            saveAuthTokenToDatabase(new Account(name, type),
8746dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                                    authTokenType, authToken);
875a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
876603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
877f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
87826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
879d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
880f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
88126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
88226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
883a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
88426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
885a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
88626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
88726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
88826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
88926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
890603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
891603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
892d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
893d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
894d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
895d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
896d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
897d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
898d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
899d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
900d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
901d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
902ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
903ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
904ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
905ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
906ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
907ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
908d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
909ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
910d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
911d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
912d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
913d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
914d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
915d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
916d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
917d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
918d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
919ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
920d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
921ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
922d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
923d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
924d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
925d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
926d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
927d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
929ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
930d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
931d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
932d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
933d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
934d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
935d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
936d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
937d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
938d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
939d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
940d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
941d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
942d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
943d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
944d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
945d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
946d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
947d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
948d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
949d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
950d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
951d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
952d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
953d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
954d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
955d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
956d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
957d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
958d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
959d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
960d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
961d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
962d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
963d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
964d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
965d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
966d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
967d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
968d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
969d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
970d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
971d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
972d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
973d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
974d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
975d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
976a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
9773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
9783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
979a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
980382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
981382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
982d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
98326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
98426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
9858570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, accountType, expectActivityLaunch,
9868570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
98726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
9883348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
9893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
99026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
991a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
99226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
99326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
9943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
9953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
9963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
9973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
9983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
99926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
100026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
100126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
100226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
100326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1004603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1005603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1006a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
1007f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
1008382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1009382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1010d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
101126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
101226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
10138570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
10148570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
101526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1016f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
101726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
101826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
101926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
102026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
102126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
102226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
102326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
102426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
102526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1026603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1027603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1028a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
1029a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
1030a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
1031382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1032382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1033382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1034d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
103526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
103626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
10378570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
10388570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
103926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
104026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
104126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
104226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
104326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
104426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
104526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
104626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
104726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
104826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
104926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
105026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
105126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
105226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1053603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1054603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1055a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
1056a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
1057382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1058382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1059d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
106026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
106126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
10628570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, accountType, expectActivityLaunch,
10638570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
106426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
106526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
106626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
106726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
106826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
106926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
107026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
107126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
107226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
107326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
107426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1075603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1076603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
10783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
10793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
10803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
10813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
10823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
10843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
10858570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, type, false /* expectActivityLaunch */,
10868570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
10873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
10883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
10913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
10923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
10933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
10943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
10953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
10973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
11003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
11013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
11023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
11033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
11043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
110529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            final IAccountAuthenticator accountAuthenticator = mAuthenticator;
110629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            if (accountAuthenticator == null) {
110729e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // It is possible that the authenticator has died, which is indicated by
110829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // mAuthenticator being set to null. If this happens then just abort.
110929e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // There is no need to send back a result or error in this case since
111029e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // that already happened when mAuthenticator was cleared.
111129e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
111229e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                    Log.v(TAG, "checkAccount: aborting session since we are no longer"
111329e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                            + " connected to the authenticator, " + toDebugString());
111429e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                }
111529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                return;
111629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            }
11173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
111829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
11193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
1120f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1121a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
11243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
11253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
11263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
1127f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
11283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
11293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1130f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
11313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
11323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
11333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
11343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
11363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
11373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
11383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
11393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
11403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
11413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
11423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
11433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
11443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
11453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
1146f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
11473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
11483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
11493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
11503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
11513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
11523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
11533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
11543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
11553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
11573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
11583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
11593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
11603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
11613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1163ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1164ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
1165ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1166ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1167ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
1168ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
1169ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1170ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1171ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1172ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1173ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1174ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
11753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
1176382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1177382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (type == null) throw new IllegalArgumentException("accountType is null");
1178d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
1179ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
11803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
11813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
1182f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "type is null");
11833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
11843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
11853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
11863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
11873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
11883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
11903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1191ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1192d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                Account[] accounts = getAccountsByType(type);
1193d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                Bundle result = new Bundle();
1194d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
1195d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                onResult(response, result);
1196ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1197ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
11983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
11993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
12003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
12013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
12033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1206ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1212603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1222603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1223603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1224603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1225603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1227603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1228603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1230603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1232b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            implements IBinder.DeathRecipient, ServiceConnection {
1233603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1234603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1235a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1236a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
12383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1243603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
12458570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana        private final boolean mStripAuthTokenFromResult;
12468570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana
1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
12488570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
1249603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1250a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
12513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
12528570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            mStripAuthTokenFromResult = stripAuthTokenFromResult;
1253603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1254603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1255a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1256a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1257a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1260a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1261a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1262a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1263a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1264a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1265a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1268a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1271603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1273a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1274a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1275a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1276a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1277a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1278a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1279a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1280a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1281a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1282a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1283a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1284a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1285a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1286a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1287a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1288a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1289a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1290a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1291a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1294a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1295a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1296a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1298a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1299a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1300a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1301a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1302a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1303a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1304a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1305a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1306a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1307a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1308a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1309a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1310a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1314a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1315a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1316a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1317b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!bindToAuthenticator(mAccountType)) {
1318a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1319f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1320603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1321603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1322603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1323603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1324603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1325603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1326b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                mContext.unbindService(this);
1327603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1328603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1329603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1330603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1331603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1332603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1333603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1334603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1335603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1336603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1338603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1339b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1340603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1341a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1342a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1343a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1344f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1345a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1346a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1349b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1350a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1352603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1353f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1356603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1358b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public abstract void run() throws RemoteException;
1359b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1360603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1361a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1362603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1363f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1364a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1365603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1366603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1367603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1368a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1369a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1370f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1371f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1372f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1373d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1374d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1375d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1376d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1378a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1379a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1380f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1381a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1382a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1383a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1387a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1388f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1389a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1390a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
13918570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        if (mStripAuthTokenFromResult) {
13928570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                            result.remove(AccountManager.KEY_AUTHTOKEN);
13938570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        }
1394a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1395a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1397a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1398a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1399a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1400a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1405a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1406a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1410a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1411a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1412a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1414a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1415a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1416a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1417a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1418a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1419a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1420a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1421a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1422a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1423a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1424a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1425a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1426a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1427a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1429a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1432b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1433b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        /**
1434b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * find the component name for the authenticator and initiate a bind
1435b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * if no authenticator or the bind fails then return false, otherwise return true
1436b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         */
1437b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        private boolean bindToAuthenticator(String authenticatorType) {
1438b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1439b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    mAuthenticatorCache.getServiceInfo(
1440b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            AuthenticatorDescription.newKey(authenticatorType));
1441b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (authenticatorInfo == null) {
1442b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1443b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "there is no authenticator for " + authenticatorType
1444b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            + ", bailing out");
1445b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1446b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1447b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1448b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1449b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            Intent intent = new Intent();
1450b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
1451b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setComponent(authenticatorInfo.componentName);
1452b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1453b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
1454b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1455b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
1456b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1457b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
1458b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1459b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1460b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1461b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1462b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1463b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            return true;
1464b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        }
1465603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1466603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1467603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1468603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1469603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1470603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
14713348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1472603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1473603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1474603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1475603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1476603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1477603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1478603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1479603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1480603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1481603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1482603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1483603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1484603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1485a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    private static String getDatabaseName() {
14861f4df90bfab8ca42eabe95f19eadff3432eee7fdOscar Montemayor        return DATABASE_NAME;
1487a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    }
1488a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1489603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1490a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1491603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1492a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            super(context, AccountManagerService.getDatabaseName(), null, DATABASE_VERSION);
1493603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1494603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1495603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1496603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1497603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1498603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1499603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1500603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1501603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1502603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1503603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1504603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1505603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1506603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1507603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1508603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1509603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1510603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1511d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1512d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1513603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1514603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1516603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1517603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1522603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1523a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1524d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1525d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1526d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1527d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1528a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1529a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1530a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1531a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1532a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1533a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1534a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1535d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1536d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1537a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1538603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1539603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1540d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1541d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1542d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1543d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1544d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1545d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1546d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1547d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1548d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1549603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1550603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1551a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1552603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1553a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1554d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1555d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1556d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1557d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1558d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1559d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1560d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1561d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1562d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1563a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1564a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
15653348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
15663348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
15673348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
15683348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
15693348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
15703348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1571603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1572603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1573603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1574603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1575603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1576603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1579603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1580603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1581603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1582603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1583603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1584603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1585603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1586603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1587603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1588603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1589603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1590603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1591603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1592603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1593603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1594603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1595603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1596603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1597603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1600603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1601603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1602603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1604603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1605603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1606603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1607603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
16093348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1612603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1613603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1614603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1615603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1616603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1617885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // Check IMSI on every update; nothing happens if the IMSI
1618885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // is missing or unchanged.
1619885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            TelephonyManager telephonyManager =
1620885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1621885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager == null) {
1622885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                Log.w(TAG, "failed to get TelephonyManager");
1623885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                return;
1624885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1625885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            String imsi = telephonyManager.getSubscriberId();
1626885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1627885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the subscriber ID is an empty string, don't do anything.
1628603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1630885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the current IMSI matches what's stored, don't do anything.
1631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1632603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1633603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1635885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (imsi.equals(storedImsi)) return;
1636885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1637885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If a CDMA phone is unprovisioned, getSubscriberId()
1638885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // will return a different value, but we *don't* erase the
1639885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // passwords.  We only erase them if it has a different
1640885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // subscriber ID once it's provisioned.
1641885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
1642885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                IBinder service = ServiceManager.checkService(Context.TELEPHONY_SERVICE);
1643885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (service == null) {
1644885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "call to checkService(TELEPHONY_SERVICE) failed");
1645885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1646885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1647885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                ITelephony telephony = ITelephony.Stub.asInterface(service);
1648885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (telephony == null) {
1649885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "failed to get ITelephony interface");
1650885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1651885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1652885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                boolean needsProvisioning;
1653885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                try {
1654885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    needsProvisioning = telephony.getCdmaNeedsProvisioning();
1655885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                } catch (RemoteException e) {
1656885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "exception while checking provisioning", e);
1657885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // default to NOT wiping out the passwords
1658885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    needsProvisioning = true;
1659885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1660885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (needsProvisioning) {
1661885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // if the phone needs re-provisioning, don't do anything.
1662885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1663885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                        Log.v(TAG, "current IMSI=" + imsi + " (needs provisioning); stored IMSI=" +
1664885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                              storedImsi);
1665885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    }
1666885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1667885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1668885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1669603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
16705b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
167127844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
167227844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1673603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1674603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1675603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1676603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1677603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
16783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1679603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1680603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1681603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1682603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1683603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1684603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1685603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1686603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1687603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1688603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1689603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1690603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1691a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16921cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
16931cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
16941cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
16951cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
16961cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
16971cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
16981cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
16991cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
17001cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
17011cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
17021cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
17031cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
1704a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1705a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
17061cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
17071cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
1708a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
17091cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
17101cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
17111cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
17121cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (isCheckinRequest) {
17131cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            // This is a checkin request. *Only* upload the account types and the count of each.
17141cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1715a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
17161cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
17171cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    null, null, ACCOUNTS_TYPE, null, null);
17181cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            try {
17191cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                while (cursor.moveToNext()) {
17201cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    // print type,count
17211cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
17221cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
17231cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            } finally {
17241cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (cursor != null) {
17251cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    cursor.close();
17261cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
17271cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
17281cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        } else {
1729c2e4691d788088b22eadc9b2d35e9bdf0b6a0ffcFred Quintana            Account[] accounts = getAccountsByType(null /* type */);
1730307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println("Accounts: " + accounts.length);
1731307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            for (Account account : accounts) {
1732307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("  " + account);
1733307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
1734307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
1735307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println();
17361cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            synchronized (mSessions) {
17371cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                final long now = SystemClock.elapsedRealtime();
1738307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("Active Sessions: " + mSessions.size());
17391cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                for (Session session : mSessions.values()) {
17401cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println("  " + session.toDebugString(now));
17411cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
17421cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
17431cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
17441cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            fout.println();
17451cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            mAuthenticatorCache.dump(fd, fout, args);
17461cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
1747a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1748a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1749d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
175026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
175126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
175226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
175326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
175426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1755a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1756d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1757d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1758d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1759d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1760d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
176133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
176233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
176533f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
176633f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
176733f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
176833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
177233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        .notify(notificationId, n);
1773d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
177426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
177526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
177626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1777a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1778a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1779d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
178026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
178126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
178226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
178426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
178526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
178626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1787a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1788d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1789b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    /** Succeeds if any of the specified permissions are granted. */
1790b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkBinderPermission(String... permissions) {
1791d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1792b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
1793b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        for (String perm : permissions) {
1794b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
1795b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1796b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                    Log.v(TAG, "caller uid " + uid + " has " + perm);
1797b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                }
1798b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                return;
1799b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            }
1800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1801b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
1802b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
1803b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        Log.w(TAG, msg);
1804b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        throw new SecurityException(msg);
1805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1806d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
18077be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
18087be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
18097be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
18107be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
18117be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
18127be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
18137be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
18147be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
18157be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
18167be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
18177be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
18187be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
18197be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
18207be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
18217be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
18227be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1824b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        final boolean inSystemImage = inSystemImage(callerUid);
182531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
182631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
182731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
182831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasExplicitlyGrantedPermission(account, authTokenType);
1829d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1830d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1831d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1832d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1833d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1834d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1835b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage;
1836d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1837d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
18381a23191bbde11505d6e0c25c04a60b41cb27fd31Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1839d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1840d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1841d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1842ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1843ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1844ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1845d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1846d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1847d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1848d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1849d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1850d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1851d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1852d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1853d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1854d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1855d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1856ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1857d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1858d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1859d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1860d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1861d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1862751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            Log.d(TAG, "no credentials permission for usage of " + account + ", "
1863d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1864d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1865d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1866d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1867d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1868d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1869d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1870d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1871d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
187231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
1873d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1874d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1875d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1876d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1877d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1878d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1879d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1880d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1881d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1882d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1883d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1884d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1885d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1886d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1887d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1888d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1889d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1890d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1891d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1892d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1893d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1894d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1895b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkManageAccountsOrUseCredentialsPermissions() {
1896b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
1897b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                Manifest.permission.USE_CREDENTIALS);
1898b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    }
1899b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
1900d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1901d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1902d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1903d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1904d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1905d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1906d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1907d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
1908382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
1909382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
191031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
191131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1912d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1913d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1914d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1915d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1916d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1917d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1918d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1919d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1920d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1921d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1922d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1923d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1924d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1925d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1926d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1927d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1929d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1930d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1931d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1932d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1933d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1934d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1935d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1936d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1937d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1938d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
1939382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
1940382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
194131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
194231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1943d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1944d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1945d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1946d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1947d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1948d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1949d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1950d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1951d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1952d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1953d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1954d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1955d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1956d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1957d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1958d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1959d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1960603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1961