AccountManagerService.java revision 9ec17366c17efd14c643ee88fa1132ab05197349
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
1956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport com.android.internal.R;
2056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport com.android.internal.telephony.ITelephony;
2156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport com.android.internal.telephony.TelephonyIntents;
2256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
23885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.Manifest;
243b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabotimport android.app.ActivityManager;
25885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.Notification;
26885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.NotificationManager;
27885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.PendingIntent;
28a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
29885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.ComponentName;
30a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
31a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
32a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
33a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
34b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintanaimport android.content.ServiceConnection;
35885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.ApplicationInfo;
36885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.PackageInfo;
37d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
38d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
393ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
40603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
41603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
42a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
43a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
44885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.os.Binder;
45a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
46a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport android.os.Environment;
47a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
48a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
49a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
50a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
51a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
53885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.os.ServiceManager;
54a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
55d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.SystemProperties;
56603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.telephony.TelephonyManager;
57a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
58a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
59d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
61a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport java.io.File;
62a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
63a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
64a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
6556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.Arrays;
66a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
67d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
6856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.LinkedHashMap;
69d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
70d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
71603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
73603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *    AccountManager accountManager =
78603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
80603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
813ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
823ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        implements RegisteredServicesCacheListener<AuthenticatorDescription> {
843348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
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
9456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final PackageManager mPackageManager;
9556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final IAccountAuthenticatorCache mAuthenticatorCache;
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final DatabaseHelper mOpenHelper;
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final SimWatcher mSimWatcher;
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
1101cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
118603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
119d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
120d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
121d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
122d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
123d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
132603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
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
14656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
14756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
14856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
14956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_AUTHTOKEN};
15056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
15156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_USERDATA_BY_ACCOUNT =
15256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
15356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
15456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
155a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
157d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
158d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
159d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            mCredentialsPermissionNotificationIds =
160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
161d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
162d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Account, Integer>();
163d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
164d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
165d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
16631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
1677be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1687be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
169f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
1707be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1717be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1727be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
17356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final Object mCacheLock = new Object();
17456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /** protected by the {@link #mCacheLock} */
17556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final HashMap<String, Account[]> mAccountCache = new HashMap<String, Account[]>();
17656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /** protected by the {@link #mCacheLock} */
17756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private HashMap<Account, HashMap<String, String>> mUserDataCache =
17856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            new HashMap<Account, HashMap<String, String>>();
17956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /** protected by the {@link #mCacheLock} */
18056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private HashMap<Account, HashMap<String, String>> mAuthTokenCache =
18156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            new HashMap<Account, HashMap<String, String>>();
18256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
184d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
185d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
187d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
188d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
189d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
190d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
191d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context) {
19456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        this(context, context.getPackageManager(), new AccountAuthenticatorCache(context));
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context, PackageManager packageManager,
19856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            IAccountAuthenticatorCache authenticatorCache) {
199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
20056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mPackageManager = packageManager;
201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper = new DatabaseHelper(mContext);
203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
206603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
20856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mAuthenticatorCache = authenticatorCache;
2095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        mAuthenticatorCache.setListener(this, null /* Handler */);
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
211885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker        mSimWatcher = new SimWatcher(mContext);
212d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
213afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
21456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        validateAccountsAndPopulateCache();
215afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana    }
216afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
21756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private void validateAccountsAndPopulateCache() {
218afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        boolean accountDeleted = false;
219afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
220afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
221afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
222afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                null, null, null, null, null);
223afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        try {
22456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            synchronized (mCacheLock) {
22556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                mAccountCache.clear();
22656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final HashMap<String, ArrayList<String>> accountNamesByType =
22756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        new HashMap<String, ArrayList<String>>();
22856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                while (cursor.moveToNext()) {
22956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final long accountId = cursor.getLong(0);
23056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cursor.getString(1);
23156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountName = cursor.getString(2);
23256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (mAuthenticatorCache.getServiceInfo(
23356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            AuthenticatorDescription.newKey(accountType)) == null) {
23456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.d(TAG, "deleting account " + accountName + " because type "
23556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + accountType + " no longer has a registered authenticator");
23656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
23756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountDeleted = true;
23856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        final Account account = new Account(accountName, accountType);
23956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        mUserDataCache.remove(account);
24056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        mAuthTokenCache.remove(account);
24156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    } else {
24256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
24356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (accountNames == null) {
24456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNames = new ArrayList<String>();
24556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNamesByType.put(accountType, accountNames);
24656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
24756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountNames.add(accountName);
24856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
24956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
25056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                for (HashMap.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
25156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cur.getKey();
25256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final ArrayList<String> accountNames = cur.getValue();
25356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final Account[] accountsForType = new Account[accountNames.size()];
25456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    int i = 0;
25556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    for (String accountName : accountNames) {
25656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountsForType[i] = new Account(accountName, accountType);
25756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ++i;
25856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
25956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    mAccountCache.put(accountType, accountsForType);
260afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                }
261afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
262afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        } finally {
263afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            cursor.close();
264afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            if (accountDeleted) {
265afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                sendAccountsChangedBroadcast();
266afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
267afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        }
2683ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
2693ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana    public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
27156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        validateAccountsAndPopulateCache();
272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
273603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
274a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
27556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
27656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getPassword: " + account
27756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
27856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
27956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
280382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
281d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
282d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
28326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
284603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
285ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
28726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
290603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
291ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
29231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
29331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
29431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
29531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
296ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
297ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
298ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
299ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
300ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
301ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
303ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
304ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
306ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
309ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
310a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
31156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
31256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getUserData: " + account
31356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
31456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
31556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
31656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
317382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
318382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
319d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
32026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
321603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
32256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return readUserDataFromCache(account, key);
323ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
324ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
325ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
326ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
3289788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
32956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
33056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthenticatorTypes: "
33156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + "caller's uid " + Binder.getCallingUid()
33256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
33356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
33426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
33526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3369788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3379788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3389788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3399788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
34026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3419788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
342718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
343718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
34426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
34526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
34626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
34726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
34826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
349a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
350a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
352a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
35356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
35456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: " + account
35556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
35656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
35756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
358382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
359d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
360d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
361603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
36226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
363603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
367ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
369ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
370ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
371ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
372743dfad2a51e016ddb741c104317637089187753Fred Quintana        if (account == null) {
373743dfad2a51e016ddb741c104317637089187753Fred Quintana            return false;
374743dfad2a51e016ddb741c104317637089187753Fred Quintana        }
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
379ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
380ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
381ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
38256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                Log.w(TAG, "insertAccountIntoDatabase: " + account
38356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        + ", skipping since the account already exists");
384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
386ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
388ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
39256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                Log.w(TAG, "insertAccountIntoDatabase: " + account
39356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        + ", skipping the DB insert failed");
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
395ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
396ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
397ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
40056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.w(TAG, "insertAccountIntoDatabase: " + account
40156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + ", skipping since insertExtra failed for key " + key);
402ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
406ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
40756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            insertAccountIntoCache(account);
408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
409ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
411afd2f549bb850828ad4961ccdae1bd5e8505baa4Fred Quintana        sendAccountsChangedBroadcast();
412743dfad2a51e016ddb741c104317637089187753Fred Quintana        return true;
413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
419603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
4233084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public void hasFeatures(IAccountManagerResponse response,
424bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            Account account, String[] features) {
42556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
42656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "hasFeatures: " + account
42756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
42856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
42956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
43056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
43156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
432382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
433382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
434382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (features == null) throw new IllegalArgumentException("features is null");
435bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        checkReadAccountsPermission();
436bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        long identityToken = clearCallingIdentity();
437bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        try {
438bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            new TestFeaturesSession(response, account, features).bind();
439bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        } finally {
440bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            restoreCallingIdentity(identityToken);
441bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
442bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
443bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
444bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    private class TestFeaturesSession extends Session {
445bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final String[] mFeatures;
446bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final Account mAccount;
447bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
448bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public TestFeaturesSession(IAccountManagerResponse response,
449bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                Account account, String[] features) {
4508570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, account.type, false /* expectActivityLaunch */,
4518570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
452bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mFeatures = features;
453bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mAccount = account;
454bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
455bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
456bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void run() throws RemoteException {
457bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            try {
458bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                mAuthenticator.hasFeatures(this, mAccount, mFeatures);
459bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            } catch (RemoteException e) {
460bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
461bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
462bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
463bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
464bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void onResult(Bundle result) {
465bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
466bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            if (response != null) {
467bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                try {
468bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (result == null) {
469bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
470bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        return;
471bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
47256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
47356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
47456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
47556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
476bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    final Bundle newResult = new Bundle();
477bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
478bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
479bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    response.onResult(newResult);
480bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                } catch (RemoteException e) {
481bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
482bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
483bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
484bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
485bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
486bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
487bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
488bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
489bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        protected String toDebugString(long now) {
4903084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana            return super.toDebugString(now) + ", hasFeatures"
491bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + mAccount
492bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
493bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
494bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
495307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
496ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
49756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
49856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "removeAccount: " + account
49956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
50056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
50156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
50256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
503382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
504382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
505d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
50626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
507ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
508ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache        cancelNotification(getSigninRequiredNotificationId(account));
509ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache        synchronized(mCredentialsPermissionNotificationIds) {
510ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            for (Pair<Pair<Account, String>, Integer> pair:
511ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                mCredentialsPermissionNotificationIds.keySet()) {
512ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                if (account.equals(pair.first.first)) {
513ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                    int id = mCredentialsPermissionNotificationIds.get(pair);
514ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                    cancelNotification(id);
515ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                }
516ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            }
517ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache        }
518ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
51926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
520ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
52126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
52226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
523a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
524603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
525603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
526ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
527ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
528ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
5298570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, account.type, false /* expectActivityLaunch */,
5308570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
531ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
532ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
533ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
534ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
536ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
537ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
538ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
543ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
544f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
545f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
546f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
547ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
548ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
549ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
550ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
551ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
55256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
55356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
55456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
55556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
556ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
557f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
558ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
559ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
560ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
561ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
562ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
563ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
564ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
565ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
567ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
568ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
56956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void removeAccount(Account account) {
570ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
571ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
572ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
57356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        removeAccountFromCache(account);
574ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
575ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
576ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
577a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
57856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
57956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "invalidateAuthToken: accountType " + accountType
58056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
58156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
58256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
583382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
584382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authToken == null) throw new IllegalArgumentException("authToken is null");
585b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkManageAccountsOrUseCredentialsPermissions();
58626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
587603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
58826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
58926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
59026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
59126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
59226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
59326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
59426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
59526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
596603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
59726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
600603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
601603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
602ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
603ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
604ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
6053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
6063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
6073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
6083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
6093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
6103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
6113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
6123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
6133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
6143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
6153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
6163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
6173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
6183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
6193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
6203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
6213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
62256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                writeAuthTokenIntoCache(new Account(accountName, accountType), authTokenType, null);
623603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
6243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
6253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
626603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
627603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
628603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
63031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
63131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
63231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
6336dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
635603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
636603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
6373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
6383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
6393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
6403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
6413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
6423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
6433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
6443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
6453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
6463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
6473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
6483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
649603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
65056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                writeAuthTokenIntoCache(account, type, authToken);
651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
652603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
653603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
654603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
655603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
656603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
657603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
658603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
659a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
66056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
66156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "peekAuthToken: " + account
66256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
66356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
66456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
66556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
666382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
667382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
668d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
66926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
67026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
67156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return readAuthTokenFromCache(account, authTokenType);
67226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
67326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
674603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
675603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
676603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
677a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
67856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
67956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
68056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
68156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
68256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
68356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
684382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
685382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
686d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
68826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
6896dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
69026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
69126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
69226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
693603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
694603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
695a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
69656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
69756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
69856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
69956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
70056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
701382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
702d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
70326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
70426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
7053ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
70626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
70726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
70826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
709603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
710603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
7113ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
71231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
71331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
71431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
715d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
716d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        db.beginTransaction();
717d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        try {
718d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            final ContentValues values = new ContentValues();
719d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
720d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            final long accountId = getAccountId(db, account);
721d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            if (accountId >= 0) {
722d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                final String[] argsAccountId = {String.valueOf(accountId)};
723d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
724d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
725d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                db.setTransactionSuccessful();
726d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            }
727d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        } finally {
728d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            db.endTransaction();
729d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        }
7303ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
7313ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
7323ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
7333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
73456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.i(TAG, "the accounts changed, sending broadcast of "
73556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                + ACCOUNTS_CHANGED_INTENT.getAction());
7363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
7373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
7383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
739a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
74056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
74156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "clearPassword: " + account
74256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
74356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
74456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
745382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
746d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
74726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
74826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
7493ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
75026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
75126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
75226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
753603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
754603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
755a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
75656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
75756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setUserData: " + account
75856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
75956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
76056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
76156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
762382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
763382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
76526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
766603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
767ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
768ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
769ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
770ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
771ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
772ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
773ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
77431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
77531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
77631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
777ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
778ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
779ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
780ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
781ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
782ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
783ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
784ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
785ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
786ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
787ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
788603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
789603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
790ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
791ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
792ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
793ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
794ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
79526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
796ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
797603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
798ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
79956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            writeUserDataIntoCache(account, key, value);
800603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
801ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
802603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
803603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
804603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
80656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (result == null) {
80756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.e(TAG, "the result is unexpectedly null", new Exception());
80856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
80956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
81056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
81156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + response);
81256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
815d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
816d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
8245f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    void getAuthTokenLabel(final IAccountManagerResponse response,
8255f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            final Account account, final String authTokenType) {
8265f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        if (account == null) throw new IllegalArgumentException("account is null");
8275f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
8285f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
8295f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
8305f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
8315f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        long identityToken = clearCallingIdentity();
8325f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        try {
8335f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            new Session(response, account.type, false,
8345f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    false /* stripAuthTokenFromResult */) {
8355f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                protected String toDebugString(long now) {
8365f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    return super.toDebugString(now) + ", getAuthTokenLabel"
8375f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                            + ", " + account
8385f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                            + ", authTokenType " + authTokenType;
8395f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
8405f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
8415f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void run() throws RemoteException {
8425f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    mAuthenticator.getAuthTokenLabel(this, authTokenType);
8435f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
8445f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
8455f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void onResult(Bundle result) {
8465f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    if (result != null) {
8475f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
8485f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        Bundle bundle = new Bundle();
8495f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
8505f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(bundle);
8515f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        return;
8525f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    } else {
8535f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(result);
8545f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    }
8555f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
8565f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            }.bind();
8575f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        } finally {
8585f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            restoreCallingIdentity(identityToken);
8595f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        }
8605f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    }
8615f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
862a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
863a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
864c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
86556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
86656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthToken: " + account
86756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
86856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
86956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", notifyOnAuthFailure " + notifyOnAuthFailure
87056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
87156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
87256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
87356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
874382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
875382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
876382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
877d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
878d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
879a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final int callerPid = Binder.getCallingPid();
880a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
881a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
882a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            mAuthenticatorCache.getServiceInfo(
883a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                    AuthenticatorDescription.newKey(account.type));
884a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean customTokens =
885a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            authenticatorInfo != null && authenticatorInfo.type.customTokens;
886a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
887a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        // skip the check if customTokens
888a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean permissionGranted = customTokens ||
889a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            permissionIsGranted(account, authTokenType, callerUid);
890a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
891c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache        final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
892c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            loginOptionsIn;
893a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        if (customTokens) {
894a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            // let authenticator know the identity of the caller
895a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
896a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            loginOptions.putInt(AccountManager.KEY_CALLER_PID, callerPid);
897a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        }
898d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
89926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
90026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
901d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
902d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
903a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            if (!customTokens && permissionGranted) {
90456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                String authToken = readAuthTokenFromCache(account, authTokenType);
905d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
90626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
907f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
908f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
909f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
910d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
911d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
912a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
913a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
914603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9158570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
9168570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    false /* stripAuthTokenFromResult */) {
91726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
91826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
91926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
92026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
92126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
92226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
92326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
92426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
925a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
92626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
927d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
929d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
930d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
931d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
932d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
933d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
93426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
935a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
93626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
93726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
938f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
939d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
940d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
941d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
942f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
943d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
944f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
945d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
946d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
947d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
948f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
94926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
950f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
951f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
95226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
953f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
95426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
95526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
95626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
957a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            if (!customTokens) {
958a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                                saveAuthTokenToDatabase(new Account(name, type),
959a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                                        authTokenType, authToken);
960a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            }
961a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
962603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
963f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
96426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
965d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
966f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
96726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
96826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
969a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
97026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
971a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
97226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
97326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
97426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
97526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
976603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
977603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
978d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
979d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
980d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
981d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
982d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
983d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
984d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
985d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
986d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
987d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
988ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
989ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
990ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
991ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
992ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
993ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
994d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
995ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
996d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
99756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        installNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
998d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
999d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
10005f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    String getAccountLabel(String accountType) {
1001d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
10025f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            mAuthenticatorCache.getServiceInfo(
10035f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    AuthenticatorDescription.newKey(accountType));
1004d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
10055f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            throw new IllegalArgumentException("unknown account type: " + accountType);
1006d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1007d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1008d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
1009d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1010d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
10115f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    serviceInfo.type.packageName, 0);
1012d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
10135f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            throw new IllegalArgumentException("unknown account type: " + accountType);
1014d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
10155f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        return authContext.getString(serviceInfo.type.labelId);
10165f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    }
10175f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
10185f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
10195f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
1020d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1021d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
10229ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // See FLAT_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
10239ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // Since it was set in Eclair+ we can't change it without breaking apps using
10249ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // the intent from a non-Activity context.
10259ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1026d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
1027d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
10285f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1029d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
1030d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
1031d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
1032d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
10335f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1034d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
1035d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1036d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1037d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
1038d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
1039d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
1040d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
1041d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
1042d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
1043d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
1044d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
1045d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1046d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
1047d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
1048d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1049d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1050d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1051d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1052d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1053d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
1054d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
1055d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
1056d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
1057d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1058d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
1059d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
1060d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1061d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1062d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1063d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1064d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
10653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
10663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
1067a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
106856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
106956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: accountType " + accountType
107056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
107156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
107256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
107356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
107456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
107556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
107656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1077382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1078382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1079d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
108026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
108126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
10828570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, accountType, expectActivityLaunch,
10838570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
108426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
10853348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
10863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
108726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1088a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
108926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
109026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
10913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
10923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
10933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
10943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
10953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
109626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
109726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
109826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
109926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
110026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1103a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
1104f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
110556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
110656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "confirmCredentials: " + account
110756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
110856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
110956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
111056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
111156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1112382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1113382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1114d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
111526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
111626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
11178570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
11188570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
111926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1120f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
112126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
112226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
112326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
112426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
112526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
112626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
112726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
112826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
112926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
1133a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
113556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
113656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "updateCredentials: " + account
113756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
113856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
113956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
114056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
114156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
114256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1143382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1144382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1145382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
114726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
114826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
11498570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, account.type, expectActivityLaunch,
11508570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
115126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
115226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
115326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
115426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
115526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
115626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
115726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
115826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
115926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
116026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
116126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
116226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
116326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
116426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1167a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
1168a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
116956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
117056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "editProperties: accountType " + accountType
117156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
117256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
117356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
117456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
117556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1176382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1177382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1178d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
117926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
118026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
11818570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            new Session(response, accountType, expectActivityLaunch,
11828570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
118326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
118426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
118526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
118626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
118726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
118826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
118926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
119026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
119126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
119226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
119326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
11963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
11973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
11983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
11993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
12003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
12013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
12033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
12048570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            super(response, type, false /* expectActivityLaunch */,
12058570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
12063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
12073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
121056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            mAccountsOfType = getAccountsByTypeFromCache(mAccountType);
12113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
12123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
12133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
12143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
12163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
12193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
12203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
12213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
12223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
12233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
122429e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            final IAccountAuthenticator accountAuthenticator = mAuthenticator;
122529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            if (accountAuthenticator == null) {
122629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // It is possible that the authenticator has died, which is indicated by
122729e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // mAuthenticator being set to null. If this happens then just abort.
122829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // There is no need to send back a result or error in this case since
122929e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // that already happened when mAuthenticator was cleared.
123029e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
123129e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                    Log.v(TAG, "checkAccount: aborting session since we are no longer"
123229e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                            + " connected to the authenticator, " + toDebugString());
123329e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                }
123429e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                return;
123529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            }
12363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
123729e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
12383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
1239f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1241603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
12433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
12443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
12453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
1246f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
12473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
12483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1249f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
12503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
12513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
12523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
12533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
1254a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
12553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
12573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
12583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
12593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
12603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
12613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
12623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
12633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
126456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
126556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
126656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
126756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
12683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
1269f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
12703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
12713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
12723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
12733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
12743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
12753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
12763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
12773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
12783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
12813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
12823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
12833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
12843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1286ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1287ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
128856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
128956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
129056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
129156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
129256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1293ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1294ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1295ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
129656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return getAccountsByTypeFromCache(type);
1297ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1298ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1299ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1300ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1301ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
13033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
130456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
130556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
130656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
130756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
130856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
130956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
131056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1311382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1312382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (type == null) throw new IllegalArgumentException("accountType is null");
1313d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
13143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
13153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1316ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
131756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                Account[] accounts = getAccountsByTypeFromCache(type);
1318d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                Bundle result = new Bundle();
1319d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
1320d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                onResult(response, result);
1321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1322ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
13233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
13243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
13253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
13263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
13273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
13283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1329603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1330603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1331ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1332603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1333603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1334603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1335603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1336603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1338603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1339603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1340603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1341603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1342603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1345603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1350603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1351603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1352603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1353603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1354603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1356a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1357b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            implements IBinder.DeathRecipient, ServiceConnection {
1358603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1359603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1360a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1361a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1362a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
13633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1364a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1365a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1366a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1367603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1368603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
13708570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana        private final boolean mStripAuthTokenFromResult;
13718570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana
1372a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
13738570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1375a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
13763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
13778570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            mStripAuthTokenFromResult = stripAuthTokenFromResult;
1378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1380a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1381a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1382a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1383a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1384a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1385a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1386a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1387a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1388a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1389a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1390a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1393a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1398a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1399a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1400a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1401a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1402a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1403a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1404a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1405a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1406a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1407a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1408a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1409a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1410a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1411a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1412a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1413a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1414a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1415a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1416a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1419a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1420a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1421a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1423a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1424a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1425a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1426a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1427a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1429a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1430a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1431a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1432a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1433a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1434a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1435a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1438603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1439a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1440a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1441a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1442b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!bindToAuthenticator(mAccountType)) {
1443a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1444f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1447603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1451b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                mContext.unbindService(this);
1452603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1453603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1454603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1455603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1456603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1457603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1458603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1459603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1460603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1461603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1462603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1463603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1464b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1465603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1466a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1467a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1468a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1469f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1470a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1471a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1472603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1473603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1474b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1475a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1476a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1477603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1478f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1479a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1480603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1481603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1482603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1483b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public abstract void run() throws RemoteException;
1484b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1485603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1486a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1487603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1488f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1489a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1490603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1491603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1492603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1493a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1494a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1495f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1496f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1497f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1498d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1499d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1500d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1501d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1502603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1503a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1504a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1505f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1506a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1507a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1508a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1509603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1510603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1511603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1512a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
151356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
151456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
151556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onError() on response " + response);
151656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1517f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1518a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1519a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
15208570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        if (mStripAuthTokenFromResult) {
15218570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                            result.remove(AccountManager.KEY_AUTHTOKEN);
15228570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        }
152356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
152456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
152556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onResult() on response " + response);
152656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1527a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1528a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1529603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1530a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1531a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1532a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1533a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1534603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1535603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1536603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1537603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1538a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1539a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1540603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1541603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1542603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1543a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1544a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1545a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1546a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
154756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, getClass().getSimpleName()
154856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            + " calling onError() on response " + response);
1549a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1550a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1551a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1552a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1553a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1554a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1555a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1556a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1557a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1558a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1559a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1560a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1561603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1562603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1563b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1564b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        /**
1565b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * find the component name for the authenticator and initiate a bind
1566b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * if no authenticator or the bind fails then return false, otherwise return true
1567b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         */
1568b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        private boolean bindToAuthenticator(String authenticatorType) {
1569b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1570b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    mAuthenticatorCache.getServiceInfo(
1571b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            AuthenticatorDescription.newKey(authenticatorType));
1572b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (authenticatorInfo == null) {
1573b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1574b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "there is no authenticator for " + authenticatorType
1575b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            + ", bailing out");
1576b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1577b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1578b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1579b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1580b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            Intent intent = new Intent();
1581b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
1582b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setComponent(authenticatorInfo.componentName);
1583b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1584b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
1585b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1586b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
1587b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1588b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
1589b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1590b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1591b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1592b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1593b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1594b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            return true;
1595b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        }
1596603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1597603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1600603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1601603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
16023348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1604603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1605603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1606603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1607603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1609603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1612603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1613603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1614603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1615603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1616a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    private static String getDatabaseName() {
1617a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        if(Environment.isEncryptedFilesystemEnabled()) {
1618a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            // Hard-coded path in case of encrypted file system
1619a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            return Environment.getSystemSecureDirectory().getPath() + File.separator + DATABASE_NAME;
1620a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        } else {
1621a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            // Regular path in case of non-encrypted file system
1622a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            return DATABASE_NAME;
1623a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        }
1624a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    }
1625a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1626603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1627a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
1628603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1629a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor            super(context, AccountManagerService.getDatabaseName(), null, DATABASE_VERSION);
1630603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1632603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1633603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1635603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1636603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1637603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1638603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1639603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1640603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1641603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1642603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1643603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1644603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1645603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1646603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1647603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1648d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1649d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1650603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1652603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1653603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1654603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1655603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1656603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1657603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1658603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1659603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1660a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1661d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1662d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1663d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1664d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1665a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1666a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1667a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1668a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1669a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1670a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1671a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1672d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1673d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1674a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1675603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1676603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1680d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1681d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1682d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1683d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1684d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1685d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1686603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1687603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1688a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1689603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1690a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1691d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1693d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1694d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1695d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1696d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1699d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1700a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1701a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
17023348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
17033348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
17043348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
17053348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
17063348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
17073348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1708603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1709603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1710603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1711603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1712603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1713603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1714603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1715603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1716603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1717603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1718603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1719603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1720603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1721603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1722603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1723603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1724603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1725603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1726603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1727603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1728603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1729603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1730603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1731603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1732603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1733603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1734603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1735603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1736603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1737603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1738603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1739603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1740603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1741603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1742603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1743603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1744603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1745603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
17463348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1747603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1748603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1749603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1750603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1751603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1752603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1753603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1754885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // Check IMSI on every update; nothing happens if the IMSI
1755885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // is missing or unchanged.
1756885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            TelephonyManager telephonyManager =
1757885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1758885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager == null) {
1759885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                Log.w(TAG, "failed to get TelephonyManager");
1760885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                return;
1761885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1762885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            String imsi = telephonyManager.getSubscriberId();
1763885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1764885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the subscriber ID is an empty string, don't do anything.
1765603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1766603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1767885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If the current IMSI matches what's stored, don't do anything.
1768603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1769603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1770603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1771603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1772885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (imsi.equals(storedImsi)) return;
1773885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker
1774885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // If a CDMA phone is unprovisioned, getSubscriberId()
1775885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // will return a different value, but we *don't* erase the
1776885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // passwords.  We only erase them if it has a different
1777885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            // subscriber ID once it's provisioned.
1778885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
1779885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                IBinder service = ServiceManager.checkService(Context.TELEPHONY_SERVICE);
1780885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (service == null) {
1781885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "call to checkService(TELEPHONY_SERVICE) failed");
1782885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1783885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1784885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                ITelephony telephony = ITelephony.Stub.asInterface(service);
1785885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (telephony == null) {
1786885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "failed to get ITelephony interface");
1787885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1788885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1789885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                boolean needsProvisioning;
1790885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                try {
17914d8ae85b5de8a90a597e4b649c6ee7208e446e3bWink Saville                    needsProvisioning = telephony.needsOtaServiceProvisioning();
1792885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                } catch (RemoteException e) {
1793885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    Log.w(TAG, "exception while checking provisioning", e);
1794885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // default to NOT wiping out the passwords
1795885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    needsProvisioning = true;
1796885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1797885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                if (needsProvisioning) {
1798885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    // if the phone needs re-provisioning, don't do anything.
1799885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1800885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                        Log.v(TAG, "current IMSI=" + imsi + " (needs provisioning); stored IMSI=" +
1801885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                              storedImsi);
1802885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    }
1803885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                    return;
1804885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker                }
1805885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongker            }
1806603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
18075b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
180827844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
180927844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1810603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1811603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1812603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1813603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1814603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
1815603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1816603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1817603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1818603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1819743dfad2a51e016ddb741c104317637089187753Fred Quintana                sendAccountsChangedBroadcast();
1820603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1821603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1822603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1823603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1824603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1825603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1826603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1827603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1828a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
18291cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
18301cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
18311cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
18321cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
18331cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
18341cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
18351cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
18361cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
18371cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
18381cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
18391cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
18401cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
1841a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1842a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
18431cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
18441cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
1845a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
18461cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
18471cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
18481cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
18491cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (isCheckinRequest) {
18501cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            // This is a checkin request. *Only* upload the account types and the count of each.
18511cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1852a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
18531cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
18541cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    null, null, ACCOUNTS_TYPE, null, null);
18551cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            try {
18561cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                while (cursor.moveToNext()) {
18571cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    // print type,count
18581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println(cursor.getString(0) + "," + cursor.getString(1));
18591cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
18601cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            } finally {
18611cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (cursor != null) {
18621cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    cursor.close();
18631cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
18641cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
18651cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        } else {
186656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Account[] accounts = getAccountsByTypeFromCache(null /* type */);
1867307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println("Accounts: " + accounts.length);
1868307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            for (Account account : accounts) {
1869307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("  " + account);
1870307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
1871307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
1872307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            fout.println();
18731cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            synchronized (mSessions) {
18741cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                final long now = SystemClock.elapsedRealtime();
1875307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                fout.println("Active Sessions: " + mSessions.size());
18761cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                for (Session session : mSessions.values()) {
18771cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    fout.println("  " + session.toDebugString(now));
18781cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
18791cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            }
18801cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
18811cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            fout.println();
18821cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            mAuthenticatorCache.dump(fd, fout, args);
18831cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
1884a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1885a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1886d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
188726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
188826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
188926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
189026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
189126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1892a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1893d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1894d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1895d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1896d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1897d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
189833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
189933f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1900d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1901d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
190233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
190333f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
190433f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
190533f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1906d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1907d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
190856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                installNotification(notificationId, n);
1909d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
191026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
191126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
191226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1913a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1914a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
191556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void installNotification(final int notificationId, final Notification n) {
191656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
191756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                .notify(notificationId, n);
191856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
191956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
192056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void cancelNotification(int id) {
192126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
192226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
192326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1924d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
192526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
192626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
192726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1928a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1929d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1930b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    /** Succeeds if any of the specified permissions are granted. */
1931b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkBinderPermission(String... permissions) {
1932d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1933b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
1934b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        for (String perm : permissions) {
1935b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
1936b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
193756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, "  caller uid " + uid + " has " + perm);
1938b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                }
1939b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                return;
1940b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            }
1941d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1942b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
1943b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
194456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.w(TAG, "  " + msg);
1945b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        throw new SecurityException(msg);
1946d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1947d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
19487be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
194956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        String[] packages = mPackageManager.getPackagesForUid(callerUid);
19507be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
19517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
195256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
195356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (packageInfo != null
195456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
19557be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
19567be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
19577be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
19587be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
19597be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
19607be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
19617be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
19627be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
19637be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1964d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1965b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        final boolean inSystemImage = inSystemImage(callerUid);
196631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
196731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
196831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
196931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasExplicitlyGrantedPermission(account, authTokenType);
1970d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1971d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
197256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + callerUid + ", " + account
1973d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1974d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1975d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1976b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage;
1977d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1978d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
19791a23191bbde11505d6e0c25c04a60b41cb27fd31Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1980d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1981d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1982d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1983ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
198456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
1985ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1986d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1987d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1988d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1989d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1990d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1991d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1992d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1993d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1994d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1995d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1996d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1997ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1998d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1999d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
20003b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabot        if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
2001d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
2002d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
2003751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            Log.d(TAG, "no credentials permission for usage of " + account + ", "
2004d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
20053b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabot                    + " but ignoring since device is in test harness.");
2006d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
2007d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2008d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
2009d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2010d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2011d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
2012d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
201331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
2014d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
2015d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
2016d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
2017d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2018d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2019d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
2020d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2021d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2022d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2023d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
2024d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
2025d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
2026d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2027d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2028d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
2029d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
2030d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2031d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2032d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
2033d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
2034d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2035d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2036b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkManageAccountsOrUseCredentialsPermissions() {
2037b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
2038b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                Manifest.permission.USE_CREDENTIALS);
2039b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    }
2040b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2041d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2042d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
2043d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2044d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2045d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2046d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2047d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2048d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
2049382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2050382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
205131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
205231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
2053d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2054d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
2055d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
2056d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
2057d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
2058d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
2059d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
2060d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
2061d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
2062d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
2063d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
2064d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2065d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
2066d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
2067d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2068d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
2069d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2070d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2071d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2072d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
2073d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
2074d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2075d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2076d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2077d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2078d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2079d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
2080382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2081382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
208231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
208331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
2084d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2085d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
2086d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
2087d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
2088d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
2089d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
2090d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
2091d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
2092d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
2093d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
2094d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
2095d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2096d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
2097d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
2098d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2099d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
2100d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
210156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
210256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    static final private String stringArrayToString(String[] value) {
210356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
210456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
210556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
210656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private void removeAccountFromCache(Account account) {
210756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
210856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            final Account[] oldAccountsForType = mAccountCache.get(account.type);
210956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (oldAccountsForType != null) {
211056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                ArrayList<Account> newAccountsList = new ArrayList<Account>();
211156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                for (Account curAccount : oldAccountsForType) {
211256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (!curAccount.equals(account)) {
211356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        newAccountsList.add(curAccount);
211456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
211556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
211656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (newAccountsList.isEmpty()) {
211756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    mAccountCache.remove(account.type);
211856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                } else {
211956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Account[] newAccountsForType = new Account[newAccountsList.size()];
212056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    newAccountsForType = newAccountsList.toArray(newAccountsForType);
212156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    mAccountCache.put(account.type, newAccountsForType);
212256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
212356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
212456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            mUserDataCache.remove(account);
212556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            mAuthTokenCache.remove(account);
212656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
212756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
212856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
212956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /**
213056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     * This assumes that the caller has already checked that the account is not already present.
213156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     */
213256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private void insertAccountIntoCache(Account account) {
213356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
213456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Account[] accountsForType = mAccountCache.get(account.type);
213556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            int oldLength = (accountsForType != null) ? accountsForType.length : 0;
213656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Account[] newAccountsForType = new Account[oldLength + 1];
213756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (accountsForType != null) {
213856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
213956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
214056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            newAccountsForType[oldLength] = account;
214156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            mAccountCache.put(account.type, newAccountsForType);
214256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
214356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
214456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
214556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected Account[] getAccountsByTypeFromCache(String accountType) {
214656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
214756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (accountType != null) {
214856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final Account[] accounts = mAccountCache.get(accountType);
214956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (accounts == null) {
215056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    return EMPTY_ACCOUNT_ARRAY;
215156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                } else {
215256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    return Arrays.copyOf(accounts, accounts.length);
215356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
215456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            } else {
215556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                int totalLength = 0;
215656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                for (Account[] accounts : mAccountCache.values()) {
215756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    totalLength += accounts.length;
215856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
215956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (totalLength == 0) {
216056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    return EMPTY_ACCOUNT_ARRAY;
216156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
216256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                Account[] accounts = new Account[totalLength];
216356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                totalLength = 0;
216456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                for (Account[] accountsOfType : mAccountCache.values()) {
216556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    System.arraycopy(accountsOfType, 0, accounts, totalLength,
216656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountsOfType.length);
216756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    totalLength += accountsOfType.length;
216856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
216956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                return accounts;
217056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
217156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
217256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
217356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
217456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void writeUserDataIntoCache(Account account, String key, String value) {
217556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
217656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            HashMap<String, String> userDataForAccount = mUserDataCache.get(account);
217756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (userDataForAccount == null) {
217856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount = readUserDataForAccountFromDatabase(account);
217956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                mUserDataCache.put(account, userDataForAccount);
218056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
218156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (value == null) {
218256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount.remove(key);
218356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            } else {
218456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount.put(key, value);
218556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
218656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
218756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
218856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
218956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void writeAuthTokenIntoCache(Account account, String key, String value) {
219056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
219156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            HashMap<String, String> authTokensForAccount = mAuthTokenCache.get(account);
219256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (authTokensForAccount == null) {
219356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount = readAuthTokensForAccountFromDatabase(account);
219456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                mAuthTokenCache.put(account, authTokensForAccount);
219556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
219656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (value == null) {
219756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount.remove(key);
219856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            } else {
219956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount.put(key, value);
220056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
220156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
220256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
220356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
220456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected String readAuthTokenFromCache(Account account, String authTokenType) {
220556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
220656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            HashMap<String, String> authTokensForAccount = mAuthTokenCache.get(account);
220756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (authTokensForAccount == null) {
220856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
220956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount = readAuthTokensForAccountFromDatabase(account);
221056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                mAuthTokenCache.put(account, authTokensForAccount);
221156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
221256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return authTokensForAccount.get(authTokenType);
221356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
221456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
221556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
221656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected String readUserDataFromCache(Account account, String key) {
221756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        synchronized (mCacheLock) {
221856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            HashMap<String, String> userDataForAccount = mUserDataCache.get(account);
221956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (userDataForAccount == null) {
222056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
222156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount = readUserDataForAccountFromDatabase(account);
222256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                mUserDataCache.put(account, userDataForAccount);
222356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
222456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return userDataForAccount.get(key);
222556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
222656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
222756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
222856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected HashMap<String, String> readUserDataForAccountFromDatabase(Account account) {
222956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> userDataForAccount = new HashMap<String, String>();
223056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
223156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS,
223256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_EXTRAS_KEY_AND_VALUE,
223356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_USERDATA_BY_ACCOUNT,
223456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
223556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
223656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
223756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
223856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String tmpkey = cursor.getString(0);
223956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String value = cursor.getString(1);
224056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount.put(tmpkey, value);
224156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
224256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
224356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
224456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
224556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return userDataForAccount;
224656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
224756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
224856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected HashMap<String, String> readAuthTokensForAccountFromDatabase(Account account) {
224956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
225056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
225156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS,
225256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
225356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_AUTHTOKENS_BY_ACCOUNT,
225456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
225556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
225656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
225756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
225856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String type = cursor.getString(0);
225956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String authToken = cursor.getString(1);
226056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount.put(type, authToken);
226156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
226256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
226356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
226456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
226556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return authTokensForAccount;
226656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
2267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
2268