AccountManagerService.java revision 86bd084cf683e9877b4146918192b3fe5e268cf5
1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
20a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
21a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
22a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
23a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
24d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
25d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
267be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.PackageInfo;
277be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintanaimport android.content.pm.ApplicationInfo;
283ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
29603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
30603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
31a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
32a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
33a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
35a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
40a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
41d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.Binder;
42d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.os.SystemProperties;
43603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.telephony.TelephonyManager;
44a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
45a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
46d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
4726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.PendingIntent;
4826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.NotificationManager;
4926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport android.app.Notification;
50d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.Manifest;
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
53a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
54a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
55a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
56a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.LinkedHashMap;
57d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
58d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
59d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
61603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport com.android.internal.telephony.TelephonyIntents;
6226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintanaimport com.android.internal.R;
63603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
64603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
65603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
66603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
67603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
68603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
69603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *    AccountManager accountManager =
70603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
72603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
733ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
743ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
753ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        implements RegisteredServicesCacheListener {
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
78603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
79603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
80d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final int DATABASE_VERSION = 3;
81603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
83603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
84603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
85603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_CONNECTED = 7;
90603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_DISCONNECTED = 8;
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AccountAuthenticatorCache mAuthenticatorCache;
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final AuthenticatorBindHelper mBindHelper;
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final DatabaseHelper mOpenHelper;
95603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final SimWatcher mSimWatcher;
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
109d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
110d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
111d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
112d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
113d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
118603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
120603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
1267be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
127a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
128d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
129d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
130d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
131d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
132d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
133d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
134d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
135d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
137d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            mCredentialsPermissionNotificationIds =
141d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new HashMap<Account, Integer>();
144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
147d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final boolean isDebuggableMonkeyBuild =
148d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            SystemProperties.getBoolean("ro.monkey", false)
149d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    && SystemProperties.getBoolean("ro.debuggable", false);
1507be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
1527be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
1537be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1547be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1557be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
157d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
158d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
159d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
161d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
162d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
163d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
164d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public class AuthTokenKey {
167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final Account mAccount;
168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public final String mAuthTokenType;
169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private final int mHashCode;
170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public AuthTokenKey(Account account, String authTokenType) {
172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccount = account;
173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthTokenType = authTokenType;
174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mHashCode = computeHashCode();
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
177603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public boolean equals(Object o) {
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (o == this) {
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!(o instanceof AuthTokenKey)) {
182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
183603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
184603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            AuthTokenKey other = (AuthTokenKey)o;
185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mAccount.equals(other.mAccount)) {
186603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return false;
187603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return (mAuthTokenType == null)
189603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    ? other.mAuthTokenType == null
190603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    : mAuthTokenType.equals(other.mAuthTokenType);
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private int computeHashCode() {
194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            int result = 17;
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + mAccount.hashCode();
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return result;
198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public int hashCode() {
201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mHashCode;
202603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
203603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
205603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManagerService(Context context) {
206603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper = new DatabaseHelper(mContext);
209603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
212603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
2153ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mAuthenticatorCache.setListener(this);
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mSimWatcher = new SimWatcher(mContext);
220d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
2213ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2223ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        onRegisteredServicesCacheChanged();
2233ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
2243ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
2253ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    public void onRegisteredServicesCacheChanged() {
2263ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        boolean accountDeleted = false;
2273ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
2283ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS,
2293ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
2303ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                null, null, null, null, null);
2313ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        try {
2323ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            while (cursor.moveToNext()) {
2333ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final long accountId = cursor.getLong(0);
2343ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountType = cursor.getString(1);
2353ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                final String accountName = cursor.getString(2);
2363ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                if (mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(accountType))
2373ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                        == null) {
2383ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    Log.d(TAG, "deleting account " + accountName + " because type "
2393ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                            + accountType + " no longer has a registered authenticator");
2403ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
2413ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                    accountDeleted= true;
2423ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                }
2433ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2443ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        } finally {
2453ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            cursor.close();
2463ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            if (accountDeleted) {
2473ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                sendAccountsChangedBroadcast();
2483ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            }
2493ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        }
250603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
251603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
252a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
253d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
254d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
25526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
256603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
257ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readPasswordFromDatabase(account);
258603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
25926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
260603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
263ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readPasswordFromDatabase(Account account) {
264ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
265ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
266ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
267ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type}, null, null, null);
268ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
269ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (cursor.moveToNext()) {
270ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return cursor.getString(0);
271ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
272ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return null;
273ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
274ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
275ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
276ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
277ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
278a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
279d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
28026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
281603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
282ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return readUserDataFromDatabase(account, key);
283ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
284ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
285ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
286ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
287ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
288ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private String readUserDataFromDatabase(Account account, String key) {
289ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
29086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
29186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                EXTRAS_ACCOUNTS_ID
29286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
29386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + EXTRAS_KEY + "=?",
29486bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, key}, null, null, null);
295ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
29686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
29786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
29986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
30186bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
302603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
304603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
3059788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
30626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
30726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
3089788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
3099788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
3109788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
3119788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
31226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
3139788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
314718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
315718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
31626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
31726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
31826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
31926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
32026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
321a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
322a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
323a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
324a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public Account[] getAccountsByType(String accountType) {
325ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
32626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
328ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
329ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
330ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                selection, selectionArgs, null, null, null);
331ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
332ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            int i = 0;
333ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Account[] accounts = new Account[cursor.getCount()];
334ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            while (cursor.moveToNext()) {
335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
336ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                i++;
337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return accounts;
339603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            cursor.close();
341603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
342603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
344a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
345d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
346d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
34826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
350ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return insertAccountIntoDatabase(account, password, extras);
351ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
352ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
353ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
354ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
355ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
356ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
357ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
358ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
359ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
360ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long numMatches = DatabaseUtils.longForQuery(db,
361ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    "select count(*) from " + TABLE_ACCOUNTS
362ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
363ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new String[]{account.name, account.type});
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (numMatches > 0) {
365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
367ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            ContentValues values = new ContentValues();
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_NAME, account.name);
369ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_TYPE, account.type);
370ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            values.put(ACCOUNTS_PASSWORD, password);
371ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
372ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
373ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return false;
374ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extras != null) {
376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (String key : extras.keySet()) {
377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    final String value = extras.getString(key);
378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (insertExtra(db, accountId, key, value) < 0) {
379ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return false;
380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
383ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            sendAccountsChangedBroadcast();
385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return true;
386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
400d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
40126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
40226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
403ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new RemoveAccountSession(response, account).bind();
40426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
40526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
406a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
409ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
410ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
411ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public RemoveAccountSession(IAccountManagerResponse response, Account account) {
412ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(response, account.type, false /* expectActivityLaunch */);
413ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
414ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
415ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
417ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
421ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
422ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
423ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
424ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
425ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY)
427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    && !result.containsKey(Constants.INTENT_KEY)) {
428ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY);
429ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
430ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    removeAccount(mAccount);
431ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
433ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
435ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed);
436ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
437ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
439ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
441ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
443ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
444ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
445ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
446ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void removeAccount(Account account) {
448ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
449ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
450ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                new String[]{account.name, account.type});
451ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        sendAccountsChangedBroadcast();
452ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
453ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
454a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
455d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
45626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
457603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
45826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
45926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            db.beginTransaction();
46026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            try {
46126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                invalidateAuthToken(db, accountType, authToken);
46226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.setTransactionSuccessful();
46326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            } finally {
46426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                db.endTransaction();
46526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
466603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
46726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
468603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
469603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
470603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
471603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
472ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
473ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
474ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
4753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
4763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
4773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
4783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
4793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
4803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
4813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
4823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
4833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
4843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
4853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
4863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
4873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
4883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
4893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
4903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
4913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
492603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
4933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
4943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
495603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
496603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
497603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
498603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
4996dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana        cancelNotification(getSigninRequiredNotificationId(account));
500603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
501603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        db.beginTransaction();
502603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
5033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            long accountId = getAccountId(db, account);
5043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountId < 0) {
5053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
5063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
5073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            db.delete(TABLE_AUTHTOKENS,
5083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
5093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    new String[]{type});
5103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            ContentValues values = new ContentValues();
5113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
5123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_TYPE, type);
5133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
5143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.setTransactionSuccessful();
516603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return true;
517603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
518603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return false;
519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.endTransaction();
521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
522603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
523603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
524603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
525603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
52686bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
52786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
52886bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                        + AUTHTOKENS_TYPE + "=?",
52986bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                new String[]{account.name, account.type, authTokenType},
53086bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                null, null, null);
531603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
53286bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            if (cursor.moveToNext()) {
53386bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana                return cursor.getString(0);
534603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
53586bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            return null;
536603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
53786bd084cf683e9877b4146918192b3fe5e268cf5Fred Quintana            cursor.close();
538603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
539603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
540603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
541a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
542d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
54326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
54426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return readAuthTokenFromDatabase(account, authTokenType);
54626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
54726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
549603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
550603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
551a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
552d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
55326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
55426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5556dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana            saveAuthTokenToDatabase(account, authTokenType, authToken);
55626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
55726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
55826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
559603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
560603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
561a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
562d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
56326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
56426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5653ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, password);
56626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
56726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
56826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
569603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
570603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
5713ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    private void setPasswordInDB(Account account, String password) {
5723ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        ContentValues values = new ContentValues();
5733ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        values.put(ACCOUNTS_PASSWORD, password);
5743ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
5753ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
5763ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana                new String[]{account.name, account.type});
5773ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        sendAccountsChangedBroadcast();
5783ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
5793ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
5803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private void sendAccountsChangedBroadcast() {
5813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
5823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
5833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
584a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
585d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
58626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
58726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
5883ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana            setPasswordInDB(account, null);
58926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
59026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
59126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
592603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
593603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
594ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void sendResult(IAccountManagerResponse response, Bundle bundle) {
595ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (response != null) {
596ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
597ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                response.onResult(bundle);
598ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
599ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // if the caller is dead then there is no one to care about remote
600ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // exceptions
601ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
602ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Log.v(TAG, "failure while notifying response", e);
603ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
604ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
605ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
606ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
607ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
608a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
609d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
61026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
612ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            writeUserdataIntoDatabase(account, key, value);
613ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
614ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
615ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
616ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
617ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
618ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void writeUserdataIntoDatabase(Account account, String key, String value) {
619ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
620ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        db.beginTransaction();
621ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
622ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long accountId = getAccountId(db, account);
623ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (accountId < 0) {
624ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
625ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
626ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            long extrasId = getExtrasId(db, accountId, key);
627ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (extrasId < 0 ) {
628ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                extrasId = insertExtra(db, accountId, key, value);
629ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (extrasId < 0) {
630603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    return;
631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
632ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } else {
633ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                ContentValues values = new ContentValues();
634ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                values.put(EXTRAS_VALUE, value);
635ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
636ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
63726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
638ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
639603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
640ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.setTransactionSuccessful();
641603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
642ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            db.endTransaction();
643603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
644603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
645603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
646d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
647d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
648d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
649d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
650d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
651d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
652d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
653d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
654d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
655d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
656d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
657d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
658a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
659a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
660a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle loginOptions) {
661d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
662d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int callerUid = Binder.getCallingUid();
663d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
664d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
66526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
66626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
667d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
668d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (permissionGranted) {
670d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String authToken = readAuthTokenFromDatabase(account, authTokenType);
671d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
67226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
67326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    result.putString(Constants.AUTHTOKEN_KEY, authToken);
674ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
675ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
676d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
677d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
678a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
679a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
680603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
681ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
68226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
68326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
68426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
68526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
68626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
68826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
68926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
690a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
69126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
692d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
693d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
694d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
695d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
696d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
697d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
698d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
69926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
700a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
70126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
70226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
703d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        if (result.containsKey(Constants.AUTH_TOKEN_LABEL_KEY)) {
704d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
705d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
706d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
707d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    result.getString(Constants.AUTH_TOKEN_LABEL_KEY));
708d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
709d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            bundle.putParcelable(Constants.INTENT_KEY, intent);
710d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
711d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
712d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
71326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        String authToken = result.getString(Constants.AUTHTOKEN_KEY);
71426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
71526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            String name = result.getString(Constants.ACCOUNT_NAME_KEY);
71626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            String type = result.getString(Constants.ACCOUNT_TYPE_KEY);
71726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
71826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                onError(Constants.ERROR_CODE_INVALID_RESPONSE,
71926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
72026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
72126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
7226dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                            saveAuthTokenToDatabase(new Account(name, type),
7236dfd1382fe43592b9602fc6553e820c64067c759Fred Quintana                                    authTokenType, authToken);
724a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
725603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
72626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        Intent intent = result.getParcelable(Constants.INTENT_KEY);
72726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (intent != null && notifyOnAuthFailure) {
728d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            doNotification(
729d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    account, result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
73026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
73126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
732a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
73326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
734a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
73526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
73626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
73726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
73826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
739603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
740603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
741d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
742d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
743d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
744d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
745d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
746d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
747d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
748d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
749d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
750d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
751ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
752ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
753ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
754ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
755ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String title = titleAndSubtitle.substring(0, index);
756ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String subtitle = titleAndSubtitle.substring(index + 1);
757d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
758ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
759d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
760d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
761d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
762d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
763d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
764d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
765d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
766d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
767d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getServiceInfo(
768ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        AuthenticatorDescription.newKey(account.type));
769d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
770ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
771d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
772d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
773d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
774d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
775d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
776d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                serviceInfo.type.packageName, 0);
777d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
778ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new IllegalArgumentException("unknown account type: " + account.type);
779d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
780d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
781d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
782d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
783d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
784d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
785d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
786d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
787d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
788d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
789d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
790d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        authContext.getString(serviceInfo.type.labelId));
791d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
792d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext.getPackageManager().getPackagesForUid(uid));
793d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
794d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
795d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
796d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
797d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
798d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
799d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
800d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mCredentialsPermissionNotificationIds) {
801d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
802d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
803d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
804d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mCredentialsPermissionNotificationIds.get(key);
805d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
806d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
807d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mCredentialsPermissionNotificationIds.put(key, id);
808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
809d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
810d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
812d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
813d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getSigninRequiredNotificationId(Account account) {
814d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
815d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        synchronized(mSigninRequiredNotificationIds) {
816d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            id = mSigninRequiredNotificationIds.get(account);
817d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
818d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
819d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mSigninRequiredNotificationIds.put(account, id);
820d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
821d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
822d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
823d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
824d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
825a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
8263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
8273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
828a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch, final Bundle options) {
829d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
83026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
83126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
83226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
83326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
8343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
8353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
83626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
837a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
83826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
83926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
8403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
8413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
8423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
8433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
8443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
84526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
84626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
84726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
84826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
84926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
850603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
851603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
852a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
853a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Account account, final boolean expectActivityLaunch) {
854d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
85526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
85626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
857ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
85826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
85926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.confirmCredentials(this, account);
86026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
86126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
86226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
86326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
86426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
86526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
86626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
86726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
86826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
869603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
870603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
871a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmPassword(IAccountManagerResponse response, final Account account,
872a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String password) {
873d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
87426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
87526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
876ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, false /* expectActivityLaunch */) {
87726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
87826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.confirmPassword(this, account, password);
87926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
88126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmPassword"
88226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
88326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
88426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
88526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
88626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
88726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
888603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
889603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
890a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
891a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
892a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
893d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
89426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
89526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
896ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            new Session(response, account.type, expectActivityLaunch) {
89726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
89826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
89926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
90026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
90126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
90226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
90326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
90426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
90526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
90626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
90726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
90826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
90926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
91026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
911603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
912603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
913a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
914a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
915d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
91626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
91726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
91826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            new Session(response, accountType, expectActivityLaunch) {
91926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
92026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
92126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
92226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
92326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
92426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
92526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
92626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
92726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
92826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
92926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
930603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
931603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
9333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
9343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
9353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
9363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
9373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
9393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
9403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(response, type, false /* expectActivityLaunch */);
9413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
9423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
9453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsOfType = getAccountsByType(mAccountType);
9463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
9473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
9483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
9493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
9543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
9553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
9563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
9603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
9613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
9623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
963a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
964603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
965603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
9673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
9683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
9693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                onError(Constants.ERROR_CODE_INVALID_RESPONSE, "null bundle");
9703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
9713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result.getBoolean(Constants.BOOLEAN_RESULT_KEY, false)) {
9733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
9743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
9763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
977a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
9783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
9803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
9813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
9823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
9833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
9843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
9853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
9863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
9883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    result.putParcelableArray(Constants.ACCOUNTS_KEY, accounts);
9893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
9903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
9913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
9923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
9933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
9943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
9953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
9963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
9973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
9983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
9993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
10003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
10013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
10023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
10033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1005ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1006ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
1007ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
1008ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1009ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
1010ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return getAccountsByType(type);
1011ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1012ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1013ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1014ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1015ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1016ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
10173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
1018d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
1019ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (features != null && type == null) {
10203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
10213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
10223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
10233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
10243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // ignore this
10253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
10263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
10273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return;
10283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
10303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1031ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1032ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                getAccountsByType(type);
1033ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1034ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
10353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
10363326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
10373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
10383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
10393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
10403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1041603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getAccountId(SQLiteDatabase db, Account account) {
1042603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1043ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1044603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1045603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1046603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1047603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1048603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1049603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1050603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1051603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1052603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1053603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1054603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
1055603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1056603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1057603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1058603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1059603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1060603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1061603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1062603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1063603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1064603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1065603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1066603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1067603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1068a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1069a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
1070603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1071603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1072a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1073a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1074a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
10753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1076a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1077a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1078a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1079603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1080603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1081603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1082a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Session(IAccountManagerResponse response, String accountType,
1083a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                boolean expectActivityLaunch) {
1084603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1085a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
10863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
1087603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1088603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1089a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1090a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1091a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1092a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1093a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1094a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1095a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1096a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1097a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1098a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1099a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1102a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1107a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1108a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1109a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1110a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1112a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1113a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1114a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1115a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1116a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1117a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1118a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1119a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1120a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1121a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1122a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1123a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1128a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1129a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1133a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1138a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1139a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1140a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1141a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1142a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1143a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1144a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1145603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1146603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1147603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1148a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1149a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1150a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1151603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (!mBindHelper.bind(mAccountType, this)) {
1152a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1153a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1154603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1155603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1156603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1157603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1158603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mBindHelper.unbind(this);
1161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1162603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1165603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1166603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1167603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1168603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1169603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1170603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1171603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1172603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1173603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onConnected(IBinder service) {
1174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1175a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1176a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1177a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1178a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1179a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1180a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1182603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1183a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void run() throws RemoteException;
1184a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1185603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onDisconnected() {
1186a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1187a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1188603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1189a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1190a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "disconnected");
1191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1192603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1194603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1195a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1197a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
1198a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "timeout");
1199603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1201603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1202a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1203a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1204a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(Constants.AUTHTOKEN_KEY))) {
1205d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String accountName = result.getString(Constants.ACCOUNT_NAME_KEY);
1206d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String accountType = result.getString(Constants.ACCOUNT_TYPE_KEY);
1207d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1208d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
1209d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    cancelNotification(getSigninRequiredNotificationId(account));
1210d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1212a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1213a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1214a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    && result.containsKey(Constants.INTENT_KEY)) {
1215a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1216a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1217a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1218603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1221a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
1222a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onError(Constants.ERROR_CODE_INVALID_RESPONSE,
1223a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1224a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1226a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1227603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1228a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1229a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1232603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1233603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1234603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1235603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1236a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1238603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1239603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1240603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1242a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1243a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
1244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1248a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: responding");
1249a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1250a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1251a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1252a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1253a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1254a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1255a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1256a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1257a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1260a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1263603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1264603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1265603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1269603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1270603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1271603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mBindHelper.handleMessage(msg)) {
1272603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return;
1273603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1274603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1275603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1276603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1277603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1278603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1279603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1280603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1281603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1282603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1283603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1284603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1285603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1286603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class DatabaseHelper extends SQLiteOpenHelper {
1287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public DatabaseHelper(Context context) {
1288603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(context, DATABASE_NAME, null, DATABASE_VERSION);
1289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1290603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1295603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1296603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1297603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1301603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1302603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1304603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1306603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1307d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1308d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1309603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1310603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1315603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1316603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1317603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1318603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1319a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1321d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1322d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1323d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1324a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1325a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1326a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1327a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1330a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1331d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1332d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1333a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1334603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1335603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1336d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1337d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1338d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1339d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1340d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1341d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1342d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1343d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1344d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1345603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1347a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1349a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1350d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1351d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1352d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1354d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1355d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1356d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1357d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1358d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1359a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1360a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1361603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1362603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1363603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1364603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1365603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1366603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1367603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1368603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private void setMetaValue(String key, String value) {
1370603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
1371603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_KEY, key);
1372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(META_VALUE, value);
1373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1375603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1376603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private String getMetaValue(String key) {
1377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
1378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
1379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (c.moveToNext()) {
1381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return c.getString(0);
1382603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1383603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return null;
1384603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1385603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            c.close();
1386603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1389603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class SimWatcher extends BroadcastReceiver {
1390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public SimWatcher(Context context) {
1391603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Re-scan the SIM card when the SIM state changes, and also if
1392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // the disk recovers from a full state (we may have failed to handle
1393603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // things properly while the disk was full).
1394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            final IntentFilter filter = new IntentFilter();
1395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            context.registerReceiver(this, filter);
1398603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1399603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1400603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        /**
1401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * Compare the IMSI to the one stored in the login service's
1402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * database.  If they differ, erase all passwords and
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         * authtokens (and store the new IMSI).
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana         */
1405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
1407603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
1408603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String imsi = ((TelephonyManager) context.getSystemService(
1409603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Context.TELEPHONY_SERVICE)).getSubscriberId();
1410603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (TextUtils.isEmpty(imsi)) return;
1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1412603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            String storedImsi = getMetaValue("imsi");
1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
1416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14185b462477a90cd08551149fc649ff3035b5331d2djsh            if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
141927844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
142027844c386e5567a91ab781265ae5ad40d0ab1e27Jim Miller                        + "stored=" + storedImsi + ", current=" + imsi + ")");
1421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                db.beginTransaction();
1423603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1424603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
1425603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
14263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    sendAccountsChangedBroadcast();
1427603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.setTransactionSuccessful();
1428603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } finally {
1429603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    db.endTransaction();
1430603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1431603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1432603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            setMetaValue("imsi", imsi);
1433603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1434603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1435603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1438603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1439a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1440a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1441a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        synchronized (mSessions) {
1442a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final long now = SystemClock.elapsedRealtime();
1443a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            fout.println("AccountManagerService: " + mSessions.size() + " sessions");
1444a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            for (Session session : mSessions.values()) {
1445a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                fout.println("  " + session.toDebugString(now));
1446a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1447a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1448a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1449a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        fout.println();
1450a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1451a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        mAuthenticatorCache.dump(fd, fout, args);
1452a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1453a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1454d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void doNotification(Account account, CharSequence message, Intent intent) {
145526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
145626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
145726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
145826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
145926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
1460a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1461d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
1462d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
1463d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
1464d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
1465d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
146633f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final Integer notificationId = getSigninRequiredNotificationId(account);
146733f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
1468d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1469d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
147033f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
147133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
147233f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
147333f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
1474d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
1475d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
1476d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
147733f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        .notify(notificationId, n);
1478d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
147926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
148026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
148126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1482a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1483a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1484d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void cancelNotification(int id) {
148526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
148626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
148726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
1488d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
148926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
149026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
149126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1492a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1493d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1494d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkBinderPermission(String permission) {
1495d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1496d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (mContext.checkCallingOrSelfPermission(permission) !=
1497d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PackageManager.PERMISSION_GRANTED) {
1498d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " lacks " + permission;
1499d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1500d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1501d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1502d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1503d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " has " + permission);
1504d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1505d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1506d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
15077be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
15087be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
15097be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
15107be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
15117be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                PackageInfo packageInfo =
15127be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                        mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
15137be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
15147be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
15157be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
15167be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
15177be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
15187be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
15197be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
15207be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
15217be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
15227be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1523d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
1524ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
1525d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
1526d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1527d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
1528d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + callerUid + ", account " + account
1529d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
1530d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
1531d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
15327be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
1533d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1534d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1535d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
1536d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
1537d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
1538d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
1539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
1540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
1541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
1542d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1543d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1544d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
1545d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1546d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1547d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
1548d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
1549d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1550d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1551d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
1552d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
1553ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                account.name, account.type};
1554d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final boolean permissionGranted =
1555d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
1556d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (!permissionGranted && isDebuggableMonkeyBuild) {
1557d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // TODO: Skip this check when running automated tests. Replace this
1558d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // with a more general solution.
1559d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, "no credentials permission for usage of " + account + ", "
1560d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + authTokenType + " by uid " + Binder.getCallingUid()
1561d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + " but ignoring since this is a monkey build");
1562d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
1563d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1564d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return permissionGranted;
1565d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1566d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1567d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
1568d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
1569ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (!hasAuthenticatorUid(account.type, uid)) {
1570d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
1571d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
1572d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
1573d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1574d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1575d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
1576d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1577d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1578d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1579d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
1580d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
1581d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
1582d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1583d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1584d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
1585d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
1586d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1587d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1588d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
1589d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
1590d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1591d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1592d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1593d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
1594d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1595d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1596d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1597d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1598d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1599d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void grantAppPermission(Account account, String authTokenType, int uid) {
1600d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1601d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1603d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1604d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1605d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                ContentValues values = new ContentValues();
1606d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_ACCOUNTS_ID, accountId);
1607d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
1608d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                values.put(GRANTS_GRANTEE_UID, uid);
1609d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
1610d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1611d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1612d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1613d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1614d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1615d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1616d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1617d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1618d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
1619d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
1620d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
1621d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
1622d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
1623d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
1624d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
1625d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
1626d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public void revokeAppPermission(Account account, String authTokenType, int uid) {
1627d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1628d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        db.beginTransaction();
1629d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1630d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            long accountId = getAccountId(db, account);
1631d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (accountId >= 0) {
1632d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.delete(TABLE_GRANTS,
1633d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
1634d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                + GRANTS_GRANTEE_UID + "=?",
1635d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        new String[]{String.valueOf(accountId), authTokenType,
1636d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                String.valueOf(uid)});
1637d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.setTransactionSuccessful();
1638d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1639d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } finally {
1640d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.endTransaction();
1641d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1642d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
1643d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1644603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1645