AccountManagerService.java revision 751fdc09bb7ab0ce6feac7b7a823e38ed858feb0
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) {
285d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
28726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
289ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
290603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
29126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
295ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
29631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
29731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
29831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
29931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
300ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
301ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
303ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
304ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
306ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
309ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
311ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
312ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
313ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
314a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
315d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
31626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
318ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
319ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
320ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
322ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
323ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
324ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
32531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
32631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
32731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
32831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
329ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
33086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
33186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                EXTRAS_ACCOUNTS_ID
33286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
33386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + EXTRAS_KEY + "=?",
33486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, key}, null, null, null);
335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
33686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
33786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
338603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
33986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
340603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
34186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
342603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
3459788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
34626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
34726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3489788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3499788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3509788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3519788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
35226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3539788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
354718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
355718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
35626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
35726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
35826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
35926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
36026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
361a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
362a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
363a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
364a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
36626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
367ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
369ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
370ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
371ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
372ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
373ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
374ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
380ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
384a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
385d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
386d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
38826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
392ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
393ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
395ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
396ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
397ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
40031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            if (account == null) {
40131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                return false;
40231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            }
40350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            boolean noBroadcast = false;
40450c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (account.type.equals(GOOGLE_ACCOUNT_TYPE)) {
40550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // Look for the 'nobroadcast' flag and remove it since we don't want it to persist
40650c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                // in the db.
40750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                noBroadcast = extras.getBoolean(NO_BROADCAST_FLAG, false);
40850c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                extras.remove(NO_BROADCAST_FLAG);
40950c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
41050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller
411ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
412ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
413ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
414ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
415ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
417ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
421ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
422ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
423ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
424ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
425ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
428ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
429ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
430ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
433603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
43550c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            if (!noBroadcast) {
43650c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller                sendAccountsChangedBroadcast();
43750c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            }
438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
439603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
442603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
447603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
451603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
4523084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public void hasFeatures(IAccountManagerResponse response,
453bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            Account account, String[] features) {
454bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        checkReadAccountsPermission();
455bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        long identityToken = clearCallingIdentity();
456bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        try {
457bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            new TestFeaturesSession(response, account, features).bind();
458bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        } finally {
459bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            restoreCallingIdentity(identityToken);
460bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
461bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
462bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
463bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    private class TestFeaturesSession extends Session {
464bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final String[] mFeatures;
465bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final Account mAccount;
466bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
467bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public TestFeaturesSession(IAccountManagerResponse response,
468bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                Account account, String[] features) {
469bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
470bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mFeatures = features;
471bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mAccount = account;
472bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
473bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
474bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void run() throws RemoteException {
475bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            try {
476bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                mAuthenticator.hasFeatures(this, mAccount, mFeatures);
477bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            } catch (RemoteException e) {
478bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
479bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
480bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
481bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
482bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void onResult(Bundle result) {
483bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
484bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            if (response != null) {
485bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                try {
486bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (result == null) {
487bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
488bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        return;
489bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
490bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    final Bundle newResult = new Bundle();
491bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
492bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
493bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    response.onResult(newResult);
494bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                } catch (RemoteException e) {
495bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
496bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
497bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
498bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
499bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
500bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
501bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
502bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
503bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        protected String toDebugString(long now) {
5043084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana            return super.toDebugString(now) + ", hasFeatures"
505bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + mAccount
506bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
507bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
508bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
509307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
510ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
511d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
51226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
51326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
514ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
51526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
51626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
517a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
520ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
521ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
522ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
523ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
524ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
525ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
526ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
527ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
528ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
529ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
530ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
531ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
532ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
533ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
534ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
536ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
537f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
538f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
539f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
543ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
544ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
545ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
546f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
547ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
548ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
549ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
550ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
551ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
552ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
553ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
554ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
555ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
556ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
557ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
558ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
559ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
560ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
561ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
562ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
563ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
564ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
565a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
566d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
56726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
568603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
56926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
57026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
57126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
57226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
57326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
57426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
57526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
57626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
57826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
579603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
580603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
581603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
582603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
583ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
584ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
585ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
5863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
5873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
5883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
5893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
5903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
5913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
5923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
5933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
5943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
5953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
5963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
5973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
5983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
5993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
6003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
6013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
6023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
6043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
6053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
606603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
607603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
609603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
61031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
61131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
61231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
6136dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
614603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
615603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
616603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
6173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
6183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
6193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
6203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
6213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
6223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
6233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
6243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
6253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
6263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
6273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
6283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
630603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
632603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
633603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
635603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
636603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
637603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
638603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
63931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || authTokenType == null) {
64031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
64131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
642603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
64386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
64486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
64586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + AUTHTOKENS_TYPE + "=?",
64686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, authTokenType},
64786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                null, null, null);
648603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
64986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
65086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
65286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
653603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
65486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
655603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
656603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
657603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
658a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
659d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
66026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
66126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
66326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
66426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
665603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
666603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
667603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
668a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
67026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
67126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6726dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
67326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
67426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
67526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
676603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
677603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
678a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
68026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
68126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6823ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
68326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
68426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
68526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
686603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
687603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
6883ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
68931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
69031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
69131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
6923ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        ContentValues values = new ContentValues();
6933ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        values.put(ACCOUNTS_PASSWORD, password);
6943ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
6953ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
6963ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{account.name, account.type});
6973ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
6983ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
6993ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
7003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
7013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
7023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
7033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
704a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
705d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
70626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
70726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
7083ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
70926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
71026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
71126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
712603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
713603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
714a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
715d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
71626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
71731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
71831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
71931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
72050c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        if (account.type.equals(GOOGLE_ACCOUNT_TYPE) && key.equals("broadcast")) {
72150c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            sendAccountsChangedBroadcast();
72250c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller            return;
72350c05f38b3728b7430dd4bb8d98565d9c5e56798Jim Miller        }
724603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
725ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
726ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
727ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
728ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
729ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
730ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
731ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
73231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
73331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
73431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
735ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
736ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
737ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
738ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
739ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
740ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
741ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
742ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
743ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
744ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
745ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
746603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
747603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
748ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
749ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
750ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
751ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
752ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
75326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
754ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
755603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
756ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
757603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
758ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
759603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
760603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
761603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
762d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
765d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
766d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
767d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
768d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
772d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
773d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
774a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
775a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
776a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
777d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
778d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
779d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
780d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
78126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
78226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
784d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
785d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
786d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
78826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
789f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
790f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
791f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
794a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
795a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
796603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
797ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
79826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
79926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
80026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
80126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
80226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
80326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
80426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
80526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
806a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
80726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
809d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
810d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
81526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
81726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
81826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
819f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
823f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
824d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
825f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
826d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
827d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
828d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
829f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
83026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
831f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
832f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
83326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
834f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
83526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
83626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
83726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
8386dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                            saveAuthTokenToDatabase(new Account(name, type),
8396dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                                    authTokenType, authToken);
840a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
841603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
842f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
84326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
845f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
84626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
84726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
848a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
84926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
850a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
85126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
85226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
85326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
85426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
855603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
856603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
857d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
858d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
859d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
860d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
861d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
862d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
863d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
864d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
865d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
866d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
867ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
868ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
869ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
870ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
871ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
872ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
873d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
874ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
875d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
876d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
877d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
878d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
879d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
880d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
881d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
882d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
883d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
884ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
885d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
886ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
887d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
888d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
889d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
890d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
891d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
892d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
893d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
894ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
895d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
896d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
897d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
898d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
899d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
900d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
901d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
902d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
903d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
904d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
905d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
906d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
907d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
908d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
909d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
910d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
911d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
912d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
913d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
914d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
915d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
916d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
917d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
918d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
919d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
920d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
921d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
922d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
923d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
924d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
925d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
926d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
927d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
929d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
930d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
931d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
932d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
933d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
934d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
935d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
936d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
937d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
938d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
939d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
940d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
941a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
9423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
9433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
944a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
945d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
94626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
94726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
94826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
94926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
9503348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
95226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
953a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
95426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
95526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
9563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
9583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
9603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
96126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
96226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
96326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
96426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
96526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
966603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
967603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
968a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
969f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
970d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
97126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
97226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
973ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
97426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
975f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
97626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
97726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
97826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
97926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
98026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
98126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
98226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
98326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
98426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
985603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
986603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
987a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
988a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
989a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
990d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
99126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
99226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
993ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
99426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
99526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
99626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
99726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
99826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
99926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
100026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
100126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
100226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
100326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
100426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
100526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
100626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
100726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1008603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1009603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1010a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
1011a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
1012d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
101326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
101426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
101526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
101626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
101726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
101826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
101926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
102026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
102126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
102226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
102326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
102426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
102526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
102626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1027603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1028603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
10303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
10313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
10323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
10333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
10343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
10363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
10373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(response, type, false /* expectActivityLaunch */);
10383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
10393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
10423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
10433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
10443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
10453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
10463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
10483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
10513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
10523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
10533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
10543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
10573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
10583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
1059f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1060a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1061603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1062603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
10643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
10653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
1066f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
10673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
10683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1069f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
10703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
10713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
10733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
1074a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
10753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
10773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
10783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
10793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
10803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
10813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
10823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
10833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
10843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
1085f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
10863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
10873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
10883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
10893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
10903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
10913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
10923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
10933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
10983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
10993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
11003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1102ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1103ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
1104ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1105ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1106ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
1107ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
1108ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1109ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1110ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1111ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1112ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1113ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
11143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
1115d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
1116ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
11173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
11183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
1119f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "type is null");
11203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
11213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
11223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
11233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
11243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
11253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
11273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1128ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1129ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                getAccountsByType(type);
1130ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1131ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
11323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
11333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
11343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
11353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
11373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1138603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1139603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1140ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1141603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1142603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1143603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1144603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1145603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1146603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1147603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1148603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1149603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1150603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1151603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1152603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1153603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1154603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1155603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1157603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1158603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1162603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1165a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1166b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            implements IBinder.DeathRecipient, ServiceConnection {
1167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1169a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1170a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1171a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
11723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1173a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1174a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1175a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1179a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
1180a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                boolean expectActivityLaunch) {
1181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1182a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
11833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
1184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1186a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1187a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1188a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1189a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1190a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1191a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1193a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1194a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1195a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1196a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1199a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1204a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1205a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1206a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1207a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1208a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1209a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1210a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1211a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1212a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1213a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1214a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1215a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1216a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1217a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1218a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1219a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1220a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1221a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1222a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1223603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1224603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1226a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1227a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1228603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1229a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1232a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1233a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1234a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1235a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1236a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1238a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1243603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1248b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!bindToAuthenticator(mAccountType)) {
1249a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1250f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1251603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1252603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1253603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1254603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1255603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1256603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1257b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                mContext.unbindService(this);
1258603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1259603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1260603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1264603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1265603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1270b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1271603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1272a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1273a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1274a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1275f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1276a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1277a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1278603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1280b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1281a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1282a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1284f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1285a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1289b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public abstract void run() throws RemoteException;
1290b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1292a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1294f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1295a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1296603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1299a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1300a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1301f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1302f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1303f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1304d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1305d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1306d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1307d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1308603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1309a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1310a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1311f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1312a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1313a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1314a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1315603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1316603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1318a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1319f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1320a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1321a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
1322a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1323a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1324603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1325a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1326a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1327a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1329603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1330603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1331603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1332603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1333a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1334a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1335603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1336603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1338a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1339a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1340a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1341603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1342a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1343a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1344a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1345a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1346a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1347a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1348a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1349a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1350a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1352a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1353a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1355a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1356a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1357a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1358603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1359603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1360b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1361b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        /**
1362b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * find the component name for the authenticator and initiate a bind
1363b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * if no authenticator or the bind fails then return false, otherwise return true
1364b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         */
1365b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        private boolean bindToAuthenticator(String authenticatorType) {
1366b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1367b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    mAuthenticatorCache.getServiceInfo(
1368b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            AuthenticatorDescription.newKey(authenticatorType));
1369b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (authenticatorInfo == null) {
1370b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1371b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "there is no authenticator for " + authenticatorType
1372b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            + ", bailing out");
1373b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1374b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1375b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1376b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1377b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            Intent intent = new Intent();
1378b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
1379b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setComponent(authenticatorInfo.componentName);
1380b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1381b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
1382b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1383b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
1384b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1385b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
1386b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1387b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1388b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1389b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1390b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1391b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            return true;
1392b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        }
1393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
13993348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1400603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1413a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    private static String getDatabaseName() {
1414a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        if(Environment.isEncryptedFilesystemEnabled()) {
1415a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            // Hard-coded path in case of encrypted file system
1416a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            return Environment.getSystemSecureDirectory().getPath() + File.separator + DATABASE_NAME;
1417a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        } else {
1418a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            // Regular path in case of non-encrypted file system
1419a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            return DATABASE_NAME;
1420a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        }
1421a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    }
1422a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1423603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1424a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1425603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1426a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            super(context, AccountManagerService.getDatabaseName(), null, DATABASE_VERSION);
1427603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1428603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1429603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1433603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1434603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1435603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1438603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1439603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1440603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1442603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1445d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1446d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1447603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1451603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1452603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1453603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1454603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1455603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1456603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1457a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1458d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1459d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1460d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1461d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1462a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1463a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1464a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1465a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1466a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1467a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1468a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1469d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1470d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1471a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1472603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1473603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1474d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1475d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1476d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1477d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1478d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1479d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1480d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1481d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1482d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1483603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1484603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1485a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1486603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1487a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1488d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1489d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1490d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1491d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1492d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1493d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1494d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1495d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1496d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1497a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1498a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
14993348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
15003348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
15013348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
15023348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
15033348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
15043348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1505603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1506603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1507603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1508603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1509603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1510603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1511603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1512603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1513603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1514603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1516603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1517603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1522603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1523603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1524603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1525603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1526603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1527603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1528603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1529603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1530603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1531603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1532603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1533603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1534603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1535603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1536603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1537603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1538603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1539603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1540603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1541603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1542603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
15433348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1544603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1545603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1546603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1547603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1549603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1550603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1551885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // Check IMSI on every update; nothing happens if the IMSI
1552885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // is missing or unchanged.
1553885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            TelephonyManager telephonyManager =
1554885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1555885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager == null) {
1556885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                Log.w(TAG, "failed to get TelephonyManager");
1557885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                return;
1558885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1559885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            String imsi = telephonyManager.getSubscriberId();
1560885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1561885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the subscriber ID is an empty string, don't do anything.
1562603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1563603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1564885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the current IMSI matches what's stored, don't do anything.
1565603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1566603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1567603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1568603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1569885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (imsi.equals(storedImsi)) return;
1570885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1571885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If a CDMA phone is unprovisioned, getSubscriberId()
1572885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // will return a different value, but we *don't* erase the
1573885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // passwords.  We only erase them if it has a different
1574885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // subscriber ID once it's provisioned.
1575885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
1576885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                IBinder service = ServiceManager.checkService(Context.TELEPHONY_SERVICE);
1577885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (service == null) {
1578885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "call to checkService(TELEPHONY_SERVICE) failed");
1579885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1580885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1581885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                ITelephony telephony = ITelephony.Stub.asInterface(service);
1582885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (telephony == null) {
1583885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "failed to get ITelephony interface");
1584885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1585885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1586885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                boolean needsProvisioning;
1587885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                try {
1588885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    needsProvisioning = telephony.getCdmaNeedsProvisioning();
1589885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                } catch (RemoteException e) {
1590885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "exception while checking provisioning", e);
1591885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // default to NOT wiping out the passwords
1592885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    needsProvisioning = true;
1593885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1594885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (needsProvisioning) {
1595885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // if the phone needs re-provisioning, don't do anything.
1596885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1597885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                        Log.v(TAG, "current IMSI=" + imsi + " (needs provisioning); stored IMSI=" +
1598885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                              storedImsi);
1599885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    }
1600885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1601885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1602885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
16045b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
160527844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
160627844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1607603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1609603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
16123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1613603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1614603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1615603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1616603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1617603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1618603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1619603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1620603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1621603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1622603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1623603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1624603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1625a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16261cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
16271cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
16281cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
16291cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
16301cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
16311cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
16321cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
16331cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
16341cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
16351cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
16361cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
16371cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
1638a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1639a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
16401cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
16411cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
1642a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16431cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
16441cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
16451cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
16461cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (isCheckinRequest) {
16471cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            // This is a checkin request. *Only* upload the account types and the count of each.
16481cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1649a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16501cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
16511cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    null, null, ACCOUNTS_TYPE, null, null);
16521cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            try {
16531cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                while (cursor.moveToNext()) {
16541cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    // print type,count
16551cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
16561cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
16571cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            } finally {
16581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (cursor != null) {
16591cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    cursor.close();
16601cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
16611cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
16621cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        } else {
1663307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Account[] accounts = getAccounts(null /* type */);
1664307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println("Accounts: " + accounts.length);
1665307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            for (Account account : accounts) {
1666307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("  " + account);
1667307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
1668307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
1669307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println();
16701cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            synchronized (mSessions) {
16711cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                final long now = SystemClock.elapsedRealtime();
1672307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("Active Sessions: " + mSessions.size());
16731cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                for (Session session : mSessions.values()) {
16741cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println("  " + session.toDebugString(now));
16751cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
16761cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
16771cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
16781cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            fout.println();
16791cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            mAuthenticatorCache.dump(fd, fout, args);
16801cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
1681a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1682a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1683d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
168426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
168526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
168626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
168726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
168826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1689a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1690d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1691d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1693d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1694d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
169533f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
169633f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
169933f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
170033f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
170133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
170233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1703d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1704d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1705d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
170633f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        .notify(notificationId, n);
1707d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
170826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
170926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
171026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1711a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1712a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1713d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
171426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
171526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
171626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1717d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
171826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
171926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
172026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1721a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1722d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1723d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkBinderPermission(String permission) {
1724d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1725d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (mContext.checkCallingOrSelfPermission(permission) !=
1726d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PackageManager.PERMISSION_GRANTED) {
1727d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " lacks " + permission;
1728d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1729d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1730d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1731d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1732d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " has " + permission);
1733d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1734d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1735d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
17367be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
17377be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
17387be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
17397be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
17407be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
17417be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
17427be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
17437be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
17447be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
17457be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
17467be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
17477be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
17487be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
17497be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
17507be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
17517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1752d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1753b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        final boolean inSystemImage = inSystemImage(callerUid);
175431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
175531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
175631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
175731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasExplicitlyGrantedPermission(account, authTokenType);
1758d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1759d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1760d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1761d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1762d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1764b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage;
1765d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1766d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
17671a23191bbde11505d6e0c25c04a60b41cb27fd31Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1768d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1771ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1772ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1773ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1774d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1775d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1776d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1777d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1778d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1779d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1780d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1781d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1782d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1784d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1785ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1786d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1788d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1789d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1790d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1791751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            Log.d(TAG, "no credentials permission for usage of " + account + ", "
1792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1794d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1795d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1796d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1797d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1798d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1799d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
180131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
1802d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1803d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1804d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1806d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1807d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1809d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1810d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1815d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1816d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1824d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1825d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1826d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1827d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1828d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1829d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1830d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1831d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
183231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null  || authTokenType == null) {
183331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
183431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1835d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1836d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1837d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1838d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1839d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1840d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1841d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1842d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1843d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1845d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1846d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1847d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1848d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1849d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1850d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1851d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1852d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1853d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1854d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1855d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1856d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1857d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1858d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1859d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1860d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1861d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
186231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null  || authTokenType == null) {
186331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
186431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
1865d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1866d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1867d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1868d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1869d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1870d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1871d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1872d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1873d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1874d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1875d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1876d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1877d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1878d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1879d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1880d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1881d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1882603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1883