AccountManagerService.java revision 27844c386e5567a91ab781265ae5ad40d0ab1e27
1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
20a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
21a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
22a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
23a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
24d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
25d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
267be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.PackageInfo;
277be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.ApplicationInfo;
28603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
29603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
30a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
31a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
32a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
33a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
35a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
40d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.Binder;
41d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.SystemProperties;
42603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.telephony.TelephonyManager;
43a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
44a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
45d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
4626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.PendingIntent;
4726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.NotificationManager;
4826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.Notification;
497be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.app.Activity;
50d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.Manifest;
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
53a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
54a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
55a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
56a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.LinkedHashMap;
57d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
58d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
59d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
61603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport com.android.internal.telephony.TelephonyIntents;
6226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport com.android.internal.R;
63603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
64603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
65603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
66603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
67603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
68603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *    AccountManager accountManager =
70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
73603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapublic class AccountManagerService extends IAccountManager.Stub {
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
78d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final int DATABASE_VERSION = 3;
79603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
80603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
81603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
83603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
84603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
85603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_CONNECTED = 7;
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_DISCONNECTED = 8;
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
90603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AccountAuthenticatorCache mAuthenticatorCache;
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AuthenticatorBindHelper mBindHelper;
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final DatabaseHelper mOpenHelper;
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final SimWatcher mSimWatcher;
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
95603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
107d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
108d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
109d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
110d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
111d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
118603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
120603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
1247be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
126d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
127d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
128d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
129d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
130d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
131d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
132d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
133d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
135d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
136d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
137d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            mCredentialsPermissionNotificationIds =
139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
141d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Account, Integer>();
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final boolean isDebuggableMonkeyBuild =
146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            SystemProperties.getBoolean("ro.monkey", false)
147d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    && SystemProperties.getBoolean("ro.debuggable", false);
1487be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1497be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
1507be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
1517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1527be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1537be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
154d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
155d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
157d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
158d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
159d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
161d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
162d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public class AuthTokenKey {
165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final Account mAccount;
166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mAuthTokenType;
167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private final int mHashCode;
168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public AuthTokenKey(Account account, String authTokenType) {
170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccount = account;
171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthTokenType = authTokenType;
172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mHashCode = computeHashCode();
173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public boolean equals(Object o) {
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (o == this) {
177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!(o instanceof AuthTokenKey)) {
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            AuthTokenKey other = (AuthTokenKey)o;
183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mAccount.equals(other.mAccount)) {
184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
186603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return (mAuthTokenType == null)
187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    ? other.mAuthTokenType == null
188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    : mAuthTokenType.equals(other.mAuthTokenType);
189603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private int computeHashCode() {
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            int result = 17;
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + mAccount.hashCode();
194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return result;
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public int hashCode() {
199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mHashCode;
200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManagerService(Context context) {
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
206603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper = new DatabaseHelper(mContext);
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
212603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mSimWatcher = new SimWatcher(mContext);
217d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
220a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
221d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
222d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
22326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
224603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
225ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
22726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
228603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
230603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
231ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
232ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
233ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
234ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
235ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
236ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
237ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
238ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
239ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
240ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
241ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
242ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
243ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
244ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
245ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
247d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
24826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
249603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
250ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
251ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
252ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
253ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
254ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
255ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
256ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
257ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
258ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
259ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
260ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
261ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
262ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return null;
263ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
264ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
265ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
266ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{key}, null, null, null);
267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            try {
268ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (cursor.moveToNext()) {
269ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return cursor.getString(0);
270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
271ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return null;
272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            } finally {
273ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                cursor.close();
274603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
275603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
276ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
277603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
278603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2809788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
28126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
28226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
2839788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
2849788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
2859788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
2869788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
28726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
2889788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
289718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
290718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
29126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
29226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
29326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
29426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
29526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
296a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
297a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
298a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
299a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
300ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
30126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
302ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
303ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
304ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
306ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
309ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
311ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
313ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
315ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
316603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
318603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
319a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
321d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
322603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
32326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
324603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
325ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
326ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
328ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
329ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
330ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
331ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
332ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
333ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
334ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
336ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
337ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
339ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
341ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
342ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
344ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
346ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
347ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
348ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
349ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
350ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
351ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
352ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
353ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
354ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
356603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
358ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
359ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            sendAccountsChangedBroadcast();
360ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
361603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
362ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
363603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
364603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
365603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
366603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
367603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
368603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
370603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
371603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
374ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
375d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
37626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
37726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
37926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
38026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
381a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
386ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
388ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
392ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
393ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
394ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
395ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
396ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
397ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
400ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
401ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY)
402ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    && !result.containsKey(Constants.INTENT_KEY)) {
403ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY);
404ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
405ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
406ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
407ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
408ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
409ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
410ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed);
411ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
412ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
413ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
414ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
415ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
417ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
421ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
422ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
423ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
424ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
425ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
428ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
429a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
430d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
43126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
43326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
43426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
43526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
43626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
43726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
43826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
43926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
44026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
44226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
446603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
448ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
449ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
4503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
4513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
4523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
4533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
4543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
4553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
4563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
4573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
4583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
4593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
4603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
4613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
4623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
4633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
4643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
4653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
4663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
467603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
4683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
4693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
470603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
471603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
472603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
473603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
474603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
475603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
476603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
4773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
4783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
4793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
4803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
4813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
4823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
4833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
4843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
4853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
4863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
4873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
4883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
489603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
490603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
491603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
492603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
493603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
494603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
495603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
496603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
497603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
498603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
499603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
500603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
501603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
502603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            long accountId = getAccountId(db, account);
503603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (accountId < 0) {
504603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
505603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
506603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return getAuthToken(db, accountId, authTokenType);
507603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
508603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
509603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
510603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
511603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
512a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
513d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
51426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
51526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
51726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
51826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
522a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
523d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
52426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
52526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
52626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            cacheAuthToken(account, authTokenType, authToken);
52726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
52826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
52926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
530603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
531603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
532a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
533d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
53426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
53526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
53626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ContentValues values = new ContentValues();
53726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            values.put(ACCOUNTS_PASSWORD, password);
53826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
53926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
5413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            sendAccountsChangedBroadcast();
54226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
54326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
54426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
545603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
546603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
5473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
5483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
5493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
5503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
551a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
552d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
55326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
55426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
55526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            setPassword(account, null);
55626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
55726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
55826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
559603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
560603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
561ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void sendResult(IAccountManagerResponse response, Bundle bundle) {
562ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (response != null) {
563ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
564ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                response.onResult(bundle);
565ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // if the caller is dead then there is no one to care about remote
567ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // exceptions
568ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
569ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Log.v(TAG, "failure while notifying response", e);
570ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
571ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
572ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
573ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
574ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
575a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
576d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
57726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
579ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
580ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
581ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
582ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
583ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
584ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
585ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
586ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
587ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
588ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
589ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
590ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
591ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
592ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
593ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
594ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
595ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
596ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
597603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
599ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
600ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
601ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
602ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
603ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
60426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
605ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
606603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
607ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
609ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
612603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
613d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
614d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
615d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
616d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
618d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
619d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
620d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
621d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
622d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
623d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
624d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
625a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
626a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
627a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
628d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
629d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
630d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
631d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
63226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
63326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
634d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
635d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
636d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
637d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
638d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
63926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
64026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    result.putString(Constants.AUTHTOKEN_KEY, authToken);
641ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
642ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
643d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
644d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
645a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
646a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
647603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
648ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
64926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
65026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
65126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
65226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
65326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
65426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
65526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
65626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
657a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
65826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
659d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
660d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
661d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
662d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
663d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
664d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
665d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
66626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
667a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
66826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
66926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
670d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        if (result.containsKey(Constants.AUTH_TOKEN_LABEL_KEY)) {
671d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
672d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
673d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
674d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    result.getString(Constants.AUTH_TOKEN_LABEL_KEY));
675d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            bundle.putParcelable(Constants.INTENT_KEY, intent);
677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
678d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
679d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
68026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        String authToken = result.getString(Constants.AUTHTOKEN_KEY);
68126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
68226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            String name = result.getString(Constants.ACCOUNT_NAME_KEY);
68326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            String type = result.getString(Constants.ACCOUNT_TYPE_KEY);
68426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
68526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                onError(Constants.ERROR_CODE_INVALID_RESPONSE,
68626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
68826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
68926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            cacheAuthToken(new Account(name, type), authTokenType, authToken);
690a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
691603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
69226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        Intent intent = result.getParcelable(Constants.INTENT_KEY);
69326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
694d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
695d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    account, result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
69626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
69726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
698a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
69926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
700a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
70126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
70226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
70326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
70426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
705603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
706603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
707d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
708d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
709d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
710d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
711d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
712d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
713d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
714d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
715d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
716d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
717d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final CharSequence subtitleFormatString =
718d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mContext.getText(R.string.permission_request_notification_subtitle);
719d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
720d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mContext.getText(R.string.permission_request_notification_title),
721ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                String.format(subtitleFormatString.toString(), account.name),
722d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
723d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
724d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
725d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
726d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
727d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
728d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
729d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
730d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
731ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
732d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
733ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
734d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
735d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
736d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
737d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
738d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
739d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
740d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
741ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
742d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
743d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
744d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
745d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
746d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
747d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
748d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
749d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
750d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
751d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
752d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
753d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
754d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
755d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
756d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
757d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
758d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
759d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
760d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
761d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
762d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
765d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
766d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
767d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
768d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
770d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
772d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
773d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
774d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
775d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
776d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
777d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
778d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
779d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
780d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
781d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
782d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
784d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
785d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
786d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
788a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
7893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
7903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
791a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
79326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
79426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
79526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
79626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
7973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
7983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
79926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
800a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
80126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
80226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
8033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
8043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
8053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
8063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
8073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
80826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
80926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
81026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
81126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
81226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
813603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
814603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
815a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Account account, final boolean expectActivityLaunch) {
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
81826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
81926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
820ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
82126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
82226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.confirmCredentials(this, account);
82326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
82426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
82526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
82626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
82726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
82826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
82926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
83026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
83126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
832603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
833603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
834a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmPassword(IAccountManagerResponse response, final Account account,
835a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String password) {
836d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
83726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
83826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
839ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, false /* expectActivityLaunch */) {
84026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
84126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.confirmPassword(this, account, password);
84226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
84326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
84426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmPassword"
84526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
84626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
84726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
84826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
84926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
85026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
851603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
852603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
853a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
854a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
855a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
856d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
85726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
85826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
859ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
86026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
86126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
86226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
86326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
86426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
86526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
86626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
86726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
86826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
86926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
87026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
87126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
87226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
87326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
874603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
875603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
876a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
877a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
878d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
87926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
88026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
88126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
88226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
88326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
88426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
88626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
88726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
88826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
89026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
89126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
89226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
893603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
894603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
8953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
8963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
8973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
8983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
8993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
9003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
9023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
9033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(response, type, false /* expectActivityLaunch */);
9043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
9053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
9083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
9093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
9103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
9113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
9123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
9143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
9173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
9183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
9193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
9233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
9243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
9253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
926a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
927603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
928603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
9303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
9313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
9323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                onError(Constants.ERROR_CODE_INVALID_RESPONSE, "null bundle");
9333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result.getBoolean(Constants.BOOLEAN_RESULT_KEY, false)) {
9363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
9373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
9393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
940a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
9413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
9433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
9443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
9453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
9463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
9473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
9483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
9493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    result.putParcelableArray(Constants.ACCOUNTS_KEY, accounts);
9523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
9533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
9543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
9553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
9563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
9643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
9653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
9663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
968ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
969ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
970ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
971ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
972ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
973ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
974ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
975ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
976ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
977ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
978ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
979ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
9803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
981d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
982ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
9833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
9843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
9853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
9863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
9873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
9883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
9893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
9913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
9933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
994ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
995ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                getAccountsByType(type);
996ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
997ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
9983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
9993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
10003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
10013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
10033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
10053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        return saveAuthTokenToDatabase(account, authTokenType, authToken);
1006603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1007603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1008603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1009603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1010ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1011603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1012603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1013603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1014603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1015603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1016603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1017603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1018603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1019603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1020603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1021603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1022603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1023603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1024603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1025603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1026603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1027603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1028603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1029603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1030603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1031603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1032603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1033603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1034603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1035603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
1036603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
1037603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
1038603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{authTokenType},
1039603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                null, null, null);
1040603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1041603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1042603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getString(0);
1043603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1044603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1045603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1046603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1047603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1048603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1049603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1050a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1051a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
1052603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1053603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1054a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1055a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1056a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
10573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1058a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1059a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1060a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1061603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1062603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1063603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1064a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
1065a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                boolean expectActivityLaunch) {
1066603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1067a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
10683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
1069603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1070603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1071a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1072a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1073a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1074a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1075a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1076a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1077a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1078a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1079a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1080a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1081a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1082603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1083603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1084a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1085603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1086603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1087603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1088603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1089a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1090a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1091a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1092a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1093a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1094a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1095a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1096a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1097a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1098a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1099a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1100a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1101a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1102a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1103a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1104a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1105a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1106a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1107a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1110a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1112a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1114a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1115a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1116a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1117a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1118a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1119a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1120a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1121a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1122a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1123a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1126a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1131a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mBindHelper.bind(mAccountType, this)) {
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1136603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1137603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1138603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1139603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1140603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1141603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1142603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mBindHelper.unbind(this);
1143603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1144603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1145603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1146603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1147603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1148603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1149603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1150603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1151603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1152603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1153603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1154603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1155603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onConnected(IBinder service) {
1156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1157a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1158a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1159a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1160a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1161a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1162a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1165a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void run() throws RemoteException;
1166a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onDisconnected() {
1168a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1169a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1171a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1172a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1177a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1179a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1180a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1184a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1185a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1186a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(Constants.AUTHTOKEN_KEY))) {
1187d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String accountName = result.getString(Constants.ACCOUNT_NAME_KEY);
1188d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String accountType = result.getString(Constants.ACCOUNT_TYPE_KEY);
1189d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1190d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1191d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1192d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1194a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1195a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1196a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    && result.containsKey(Constants.INTENT_KEY)) {
1197a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1198a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1199a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1203a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1204a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onError(Constants.ERROR_CODE_INVALID_RESPONSE,
1205a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1206a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
1207a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1208a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1210a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1211a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1212a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1213a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1218a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1219a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1222603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1223a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1224a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1227a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1228a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1229a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1232a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1233a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1234a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1235a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1236a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1238a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1242a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1243603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1245603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1246603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1247603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1248603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1249603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1250603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1251603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1252603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1253603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mBindHelper.handleMessage(msg)) {
1254603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return;
1255603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1256603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1257603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1258603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1259603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1260603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1264603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1265603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(context, DATABASE_NAME, null, DATABASE_VERSION);
1271603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1273603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1274603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1275603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1276603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1277603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1278603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1280603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1281603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1282603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1284603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1285603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1289d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1290d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1295603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1296603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1301a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1302d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1303d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1304d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1305d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1306a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1307a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1308a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1309a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1310a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1311a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1312a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1313d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1314d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1315a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1316603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1318d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1319d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1321d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1322d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1323d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1324d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1325d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1326d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1327603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1328603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1330603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1331a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1332d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1333d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1334d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1335d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1336d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1337d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1338d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1339d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1340d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1341a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1342a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1345603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1350603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1351603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1352603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1353603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1354603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1356603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1358603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1359603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1360603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1361603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1362603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1363603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1364603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1365603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1366603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1367603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1368603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1370603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1371603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1375603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1376603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
1390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String imsi = ((TelephonyManager) context.getSystemService(
1391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Context.TELEPHONY_SERVICE)).getSubscriberId();
1392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1399603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14005b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
140127844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
140227844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
14083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1419603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1421a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1422a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1423a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        synchronized (mSessions) {
1424a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final long now = SystemClock.elapsedRealtime();
1425a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            fout.println("AccountManagerService: " + mSessions.size() + " sessions");
1426a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            for (Session session : mSessions.values()) {
1427a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                fout.println("  " + session.toDebugString(now));
1428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1429a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1430a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1431a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        fout.println();
1432a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1433a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        mAuthenticatorCache.dump(fd, fout, args);
1434a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1435a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1436d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
143726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
143826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
143926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
144026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
144126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1442a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1443d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1444d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1445d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1446d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1447d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
1448d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1449d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
1450d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                n.setLatestEventInfo(mContext, mContext.getText(R.string.notification_title),
1451d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1452d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1453d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1454d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        .notify(getSigninRequiredNotificationId(account), n);
1455d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
145626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
145726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
145826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1459a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1460a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1461d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
146226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
146326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
146426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1465d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
146626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
146726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
146826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1469a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1470d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1471d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkBinderPermission(String permission) {
1472d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1473d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (mContext.checkCallingOrSelfPermission(permission) !=
1474d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PackageManager.PERMISSION_GRANTED) {
1475d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " lacks " + permission;
1476d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1477d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1478d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1479d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1480d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " has " + permission);
1481d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1482d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1483d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
14847be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
14857be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
14867be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
14877be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
14887be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
14897be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
14907be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
14917be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
14927be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
14937be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
14947be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
14957be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
14967be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
14977be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
14987be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
14997be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1500d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1501ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
1502d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
1503d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1504d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1505d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1506d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1507d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1508d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
15097be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
1510d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1511d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1512d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1513d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1514d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1515d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1516ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1517ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1518ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1519d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1520d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1521d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1522d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1523d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1524d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1525d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1526d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1527d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1528d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1529d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1530ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1531d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1532d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1533d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1534d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1535d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1536d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, "no credentials permission for usage of " + account + ", "
1537d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1538d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1539d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1540d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1541d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1542d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1543d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1544d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1545d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1546ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (!hasAuthenticatorUid(account.type, uid)) {
1547d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1548d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1549d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1550d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1551d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1552d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1553d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1554d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1555d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1556d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1557d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1558d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1559d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1560d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1561d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1562d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1563d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1564d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1565d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1566d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1567d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1568d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1569d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1570d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1571d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1572d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1573d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1574d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1575d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1576d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
1577d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1578d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1579d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1580d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1581d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1582d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1583d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1584d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1585d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1586d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1587d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1588d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1589d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1590d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1591d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1592d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1593d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1594d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1595d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1596d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1597d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1598d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1599d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1600d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1601d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1603d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
1604d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1605d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1606d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1607d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1608d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1609d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1610d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1611d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1612d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1613d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1614d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1615d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1616d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1618d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1619d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1620d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1621603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1622