Automated import from //branches/master/...@142414,142414
This commit is contained in:
committed by
The Android Open Source Project
parent
d86c782127
commit
603073430b
10
Android.mk
10
Android.mk
@@ -52,7 +52,10 @@ LOCAL_SRC_FILES := $(filter-out \
|
||||
##
|
||||
## READ ME: ########################################################
|
||||
LOCAL_SRC_FILES += \
|
||||
core/java/android/accounts/IAccountsService.aidl \
|
||||
core/java/android/accounts/IAccountManager.aidl \
|
||||
core/java/android/accounts/IAccountManagerResponse.aidl \
|
||||
core/java/android/accounts/IAccountAuthenticator.aidl \
|
||||
core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
|
||||
core/java/android/app/IActivityPendingResult.aidl \
|
||||
core/java/android/app/IActivityWatcher.aidl \
|
||||
core/java/android/app/IAlarmManager.aidl \
|
||||
@@ -161,7 +164,10 @@ framework_built := $(LOCAL_BUILT_MODULE)
|
||||
# relative to the root of the build tree.
|
||||
# ============================================================
|
||||
aidl_files := \
|
||||
frameworks/base/core/java/android/accounts/IAccountsService.aidl \
|
||||
frameworks/base/core/java/android/accounts/IAccountManager.aidl \
|
||||
frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \
|
||||
frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl \
|
||||
frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
|
||||
frameworks/base/core/java/android/app/Notification.aidl \
|
||||
frameworks/base/core/java/android/app/PendingIntent.aidl \
|
||||
frameworks/base/core/java/android/content/ComponentName.aidl \
|
||||
|
||||
2376
api/current.xml
2376
api/current.xml
File diff suppressed because it is too large
Load Diff
126
core/java/android/accounts/AbstractAccountAuthenticator.java
Normal file
126
core/java/android/accounts/AbstractAccountAuthenticator.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator
|
||||
* binder interface and also provides helper libraries to simplify the creation of
|
||||
* AccountAuthenticators.
|
||||
*/
|
||||
public abstract class AbstractAccountAuthenticator {
|
||||
private static final String TAG = "AccountAuthenticator";
|
||||
|
||||
class Transport extends IAccountAuthenticator.Stub {
|
||||
public void addAccount(IAccountAuthenticatorResponse response, String accountType)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.addAccount(new AccountAuthenticatorResponse(response),
|
||||
accountType);
|
||||
}
|
||||
|
||||
public void authenticateAccount(IAccountAuthenticatorResponse
|
||||
response, String name, String type, String password)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.authenticateAccount(
|
||||
new AccountAuthenticatorResponse(response), new Account(name, type), password);
|
||||
}
|
||||
|
||||
public void getAuthToken(IAccountAuthenticatorResponse response,
|
||||
String name, String type, String authTokenType)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.getAuthToken(
|
||||
new AccountAuthenticatorResponse(response),
|
||||
new Account(name, type), authTokenType);
|
||||
}
|
||||
|
||||
public void getPasswordStrength(IAccountAuthenticatorResponse response,
|
||||
String accountType, String password)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.getPasswordStrength(
|
||||
new AccountAuthenticatorResponse(response), accountType, password);
|
||||
}
|
||||
|
||||
public void checkUsernameExistence(IAccountAuthenticatorResponse response,
|
||||
String accountType, String username)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.checkUsernameExistence(
|
||||
new AccountAuthenticatorResponse(response), accountType, username);
|
||||
}
|
||||
|
||||
public void updatePassword(IAccountAuthenticatorResponse response, String name, String type)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.updatePassword(
|
||||
new AccountAuthenticatorResponse(response), new Account(name, type));
|
||||
}
|
||||
|
||||
public void editProperties(IAccountAuthenticatorResponse response, String accountType)
|
||||
throws RemoteException {
|
||||
AbstractAccountAuthenticator.this.editProperties(
|
||||
new AccountAuthenticatorResponse(response), accountType);
|
||||
}
|
||||
}
|
||||
|
||||
Transport mTransport = new Transport();
|
||||
|
||||
/**
|
||||
* @return the IAccountAuthenticator binder transport object
|
||||
*/
|
||||
public final IAccountAuthenticator getIAccountAuthenticator()
|
||||
{
|
||||
return mTransport;
|
||||
}
|
||||
|
||||
/**
|
||||
* prompts the user for account information and adds the result to the IAccountManager
|
||||
*/
|
||||
public abstract void addAccount(AccountAuthenticatorResponse response, String accountType);
|
||||
|
||||
/**
|
||||
* prompts the user for the credentials of the account
|
||||
*/
|
||||
public abstract void authenticateAccount(AccountAuthenticatorResponse response,
|
||||
Account account, String password);
|
||||
|
||||
/**
|
||||
* gets the password by either prompting the user or querying the IAccountManager
|
||||
*/
|
||||
public abstract void getAuthToken(AccountAuthenticatorResponse response,
|
||||
Account account, String authTokenType);
|
||||
|
||||
/**
|
||||
* does local analysis or uses a service in the cloud
|
||||
*/
|
||||
public abstract void getPasswordStrength(AccountAuthenticatorResponse response,
|
||||
String accountType, String password);
|
||||
|
||||
/**
|
||||
* checks with the login service in the cloud
|
||||
*/
|
||||
public abstract void checkUsernameExistence(AccountAuthenticatorResponse response,
|
||||
String accountType, String username);
|
||||
|
||||
/**
|
||||
* prompts the user for a new password and writes it to the IAccountManager
|
||||
*/
|
||||
public abstract void updatePassword(AccountAuthenticatorResponse response, Account account);
|
||||
|
||||
/**
|
||||
* launches an activity that lets the user edit and set the properties for an authenticator
|
||||
*/
|
||||
public abstract void editProperties(AccountAuthenticatorResponse response, String accountType);
|
||||
}
|
||||
19
core/java/android/accounts/Account.aidl
Normal file
19
core/java/android/accounts/Account.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
parcelable Account;
|
||||
77
core/java/android/accounts/Account.java
Normal file
77
core/java/android/accounts/Account.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
/**
|
||||
* Value type that represents an Account in the {@link AccountManager}. This object is
|
||||
* {@link Parcelable} and also overrides {@link #equals} and {@link #hashCode}, making it
|
||||
* suitable for use as the key of a {@link java.util.Map}
|
||||
*/
|
||||
public class Account implements Parcelable {
|
||||
public final String mName;
|
||||
public final String mType;
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Account)) return false;
|
||||
final Account other = (Account)o;
|
||||
return mName.equals(other.mName) && mType.equals(other.mType);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + mName.hashCode();
|
||||
result = 31 * result + mType.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Account(String name, String type) {
|
||||
mName = name;
|
||||
mType = type;
|
||||
}
|
||||
|
||||
public Account(Parcel in) {
|
||||
mName = in.readString();
|
||||
mType = in.readString();
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mName);
|
||||
dest.writeString(mType);
|
||||
}
|
||||
|
||||
public static final Creator<Account> CREATOR = new Creator<Account>() {
|
||||
public Account createFromParcel(Parcel source) {
|
||||
return new Account(source);
|
||||
}
|
||||
|
||||
public Account[] newArray(int size) {
|
||||
return new Account[size];
|
||||
}
|
||||
};
|
||||
|
||||
public String toString() {
|
||||
return "Account {name=" + mName + ", type=" + mType + "}";
|
||||
}
|
||||
}
|
||||
197
core/java/android/accounts/AccountAuthenticatorCache.java
Normal file
197
core/java/android/accounts/AccountAuthenticatorCache.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.content.*;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.util.Log;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Xml;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
/**
|
||||
* A cache of services that export the {@link IAccountAuthenticator} interface. This cache
|
||||
* is built by interrogating the {@link PackageManager} and is updated as packages are added,
|
||||
* removed and changed. The authenticators are referred to by their account type and
|
||||
* are made available via the {@link #getAuthenticatorInfo(String type)} method.
|
||||
*/
|
||||
public class AccountAuthenticatorCache {
|
||||
private static final String TAG = "Account";
|
||||
|
||||
private static final String SERVICE_INTERFACE = "android.accounts.AccountAuthenticator";
|
||||
private static final String SERVICE_META_DATA = "android.accounts.AccountAuthenticator";
|
||||
|
||||
private volatile Map<String, AuthenticatorInfo> mAuthenticators;
|
||||
|
||||
private final Context mContext;
|
||||
private BroadcastReceiver mReceiver;
|
||||
|
||||
public AccountAuthenticatorCache(Context context) {
|
||||
mContext = context;
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
buildAuthenticatorList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void monitorPackageChanges() {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||
mContext.registerReceiver(mReceiver, intentFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Value type that describes an AccountAuthenticator. The information within can be used
|
||||
* to bind to its {@link IAccountAuthenticator} interface.
|
||||
*/
|
||||
public class AuthenticatorInfo {
|
||||
public final String mType;
|
||||
public final String mComponentShortName;
|
||||
public final ComponentName mComponentName;
|
||||
|
||||
private AuthenticatorInfo(String type, ComponentName componentName) {
|
||||
mType = type;
|
||||
mComponentName = componentName;
|
||||
mComponentShortName = componentName.flattenToShortString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the registered authenticators.
|
||||
* @param type the account type of the authenticator
|
||||
* @return the AuthenticatorInfo that matches the account type or null if none is present
|
||||
*/
|
||||
public AuthenticatorInfo getAuthenticatorInfo(String type) {
|
||||
if (mAuthenticators == null) {
|
||||
monitorPackageChanges();
|
||||
buildAuthenticatorList();
|
||||
}
|
||||
return mAuthenticators.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a collection of {@link AuthenticatorInfo} objects for all
|
||||
* registered authenticators.
|
||||
*/
|
||||
public Collection<AuthenticatorInfo> getAllAuthenticators() {
|
||||
if (mAuthenticators == null) {
|
||||
monitorPackageChanges();
|
||||
buildAuthenticatorList();
|
||||
}
|
||||
return Collections.unmodifiableCollection(mAuthenticators.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the monitoring of package additions, removals and changes.
|
||||
*/
|
||||
public void close() {
|
||||
if (mReceiver != null) {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
mReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
if (mReceiver != null) {
|
||||
Log.e(TAG, "AccountAuthenticatorCache finalized without being closed");
|
||||
}
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private void buildAuthenticatorList() {
|
||||
Map<String, AuthenticatorInfo> authenticators = Maps.newHashMap();
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
List<ResolveInfo> services =
|
||||
pm.queryIntentServices(new Intent(SERVICE_INTERFACE), PackageManager.GET_META_DATA);
|
||||
|
||||
for (ResolveInfo resolveInfo : services) {
|
||||
try {
|
||||
AuthenticatorInfo info = parseAuthenticatorInfo(resolveInfo);
|
||||
if (info != null) {
|
||||
authenticators.put(info.mType, info);
|
||||
} else {
|
||||
Log.w(TAG, "Unable to load input method " + resolveInfo.toString());
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
mAuthenticators = authenticators;
|
||||
}
|
||||
|
||||
public AuthenticatorInfo parseAuthenticatorInfo(ResolveInfo service)
|
||||
throws XmlPullParserException, IOException {
|
||||
ServiceInfo si = service.serviceInfo;
|
||||
ComponentName componentName = new ComponentName(si.packageName, si.name);
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
String authenticatorType = null;
|
||||
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = si.loadXmlMetaData(pm, SERVICE_META_DATA);
|
||||
if (parser == null) {
|
||||
throw new XmlPullParserException("No " + SERVICE_META_DATA + " meta-data");
|
||||
}
|
||||
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
int type;
|
||||
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& type != XmlPullParser.START_TAG) {
|
||||
}
|
||||
|
||||
String nodeName = parser.getName();
|
||||
if (!"account-authenticator".equals(nodeName)) {
|
||||
throw new XmlPullParserException(
|
||||
"Meta-data does not start with account-authenticator tag");
|
||||
}
|
||||
|
||||
TypedArray sa = mContext.getResources().obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AccountAuthenticator);
|
||||
authenticatorType = sa.getString(
|
||||
com.android.internal.R.styleable.AccountAuthenticator_accountType);
|
||||
sa.recycle();
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
|
||||
if (authenticatorType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AuthenticatorInfo(authenticatorType, componentName);
|
||||
}
|
||||
}
|
||||
67
core/java/android/accounts/AccountAuthenticatorResponse.java
Normal file
67
core/java/android/accounts/AccountAuthenticatorResponse.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Object that wraps calls to an {@link IAccountAuthenticatorResponse} object.
|
||||
* TODO: this interface is still in flux
|
||||
*/
|
||||
public class AccountAuthenticatorResponse {
|
||||
private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
|
||||
|
||||
public AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
|
||||
mAccountAuthenticatorResponse = response;
|
||||
}
|
||||
|
||||
public void onFinished(int result) {
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onIntResult(result);
|
||||
} catch (RemoteException e) {
|
||||
// this should never happen
|
||||
}
|
||||
}
|
||||
|
||||
public void onFinished(String result) {
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onStringResult(result);
|
||||
} catch (RemoteException e) {
|
||||
// this should never happen
|
||||
}
|
||||
}
|
||||
|
||||
public void onFinished(boolean result) {
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onBooleanResult(result);
|
||||
} catch (RemoteException e) {
|
||||
// this should never happen
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onError(errorCode, errorMessage);
|
||||
} catch (RemoteException e) {
|
||||
// this should never happen
|
||||
}
|
||||
}
|
||||
|
||||
public IAccountAuthenticatorResponse getIAccountAuthenticatorResponse() {
|
||||
return mAccountAuthenticatorResponse;
|
||||
}
|
||||
}
|
||||
306
core/java/android/accounts/AccountManager.java
Normal file
306
core/java/android/accounts/AccountManager.java
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.os.Bundle;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
|
||||
/**
|
||||
* A class that helps with interactions with the {@link IAccountManager} interface. It provides
|
||||
* methods to allow for account, password, and authtoken management for all accounts on the
|
||||
* device. Some of these calls are implemented with the help of the corresponding
|
||||
* {@link IAccountAuthenticator} services. One accesses the {@link AccountManager} by calling:
|
||||
* AccountManager accountManager =
|
||||
* (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
|
||||
*
|
||||
* <p>
|
||||
* TODO: this interface is still in flux
|
||||
*/
|
||||
public class AccountManager {
|
||||
private static final String TAG = "AccountManager";
|
||||
|
||||
private final Context mContext;
|
||||
private final IAccountManager mService;
|
||||
|
||||
public AccountManager(Context context, IAccountManager service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
public String getPassword(Account account) {
|
||||
try {
|
||||
return mService.getPassword(account);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserData(Account account, String key) {
|
||||
try {
|
||||
return mService.getUserData(account, key);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Account[] blockingGetAccounts() {
|
||||
try {
|
||||
return mService.getAccounts();
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void getAccounts(final PendingIntent intent, final int code) {
|
||||
getAccountsByType(null /* all account types */, intent, code);
|
||||
}
|
||||
|
||||
public void getAccountsByType(final String accountType,
|
||||
final PendingIntent intent, final int code) {
|
||||
Thread t = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
Account[] accounts;
|
||||
if (accountType != null) {
|
||||
accounts = blockingGetAccountsByType(accountType);
|
||||
} else {
|
||||
accounts = blockingGetAccounts();
|
||||
}
|
||||
Intent payload = new Intent();
|
||||
payload.putExtra("accounts", accounts);
|
||||
intent.send(mContext, code, payload);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
// the pending intent is no longer accepting results, we don't
|
||||
// need to do anything to handle this
|
||||
}
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
public Account[] blockingGetAccountsByType(String accountType) {
|
||||
try {
|
||||
return mService.getAccountsByType(accountType);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addAccount(Account account, String password, Bundle extras) {
|
||||
try {
|
||||
return mService.addAccount(account, password, extras);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAccount(Account account) {
|
||||
try {
|
||||
mService.removeAccount(account);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidateAuthToken(String accountType, String authToken) {
|
||||
try {
|
||||
mService.invalidateAuthToken(accountType, authToken);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public String peekAuthToken(Account account, String authTokenType) {
|
||||
try {
|
||||
return mService.peekAuthToken(account, authTokenType);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPassword(Account account, String password) {
|
||||
try {
|
||||
mService.setPassword(account, password);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPassword(Account account) {
|
||||
try {
|
||||
mService.clearPassword(account);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void setUserData(Account account, String key, String value) {
|
||||
try {
|
||||
mService.setUserData(account, key, value);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void getAuthToken(AccountManagerResponse response,
|
||||
Account account, String authTokenType, boolean notifyAuthFailure) {
|
||||
try {
|
||||
mService.getAuthToken(response.getIAccountManagerResponse(), account, authTokenType,
|
||||
notifyAuthFailure);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthToken(Account account, String authTokenType, String authToken) {
|
||||
try {
|
||||
mService.setAuthToken(account, authTokenType, authToken);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void addAccountInteractively(AccountManagerResponse response, String accountType) {
|
||||
try {
|
||||
mService.addAccountInteractively(response.getIAccountManagerResponse(), accountType);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthenticateAccountThread extends Thread {
|
||||
public Lock mLock = new ReentrantLock();
|
||||
public Condition mCondition = mLock.newCondition();
|
||||
volatile boolean mSuccess = false;
|
||||
volatile boolean mFailure = false;
|
||||
volatile boolean mResult = false;
|
||||
private final Account mAccount;
|
||||
private final String mPassword;
|
||||
public AuthenticateAccountThread(Account account, String password) {
|
||||
mAccount = account;
|
||||
mPassword = password;
|
||||
}
|
||||
public void run() {
|
||||
try {
|
||||
IAccountManagerResponse response = new IAccountManagerResponse.Stub() {
|
||||
public void onStringResult(String value) throws RemoteException {
|
||||
}
|
||||
|
||||
public void onIntResult(int value) throws RemoteException {
|
||||
}
|
||||
|
||||
public void onBooleanResult(boolean value) throws RemoteException {
|
||||
mLock.lock();
|
||||
try {
|
||||
if (!mFailure && !mSuccess) {
|
||||
mSuccess = true;
|
||||
mResult = value;
|
||||
mCondition.signalAll();
|
||||
}
|
||||
} finally {
|
||||
mLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
mLock.lock();
|
||||
try {
|
||||
if (!mFailure && !mSuccess) {
|
||||
mFailure = true;
|
||||
mCondition.signalAll();
|
||||
}
|
||||
} finally {
|
||||
mLock.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mService.authenticateAccount(response, mAccount, mPassword);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean authenticateAccount(Account account, String password) {
|
||||
AuthenticateAccountThread thread = new AuthenticateAccountThread(account, password);
|
||||
thread.mLock.lock();
|
||||
thread.start();
|
||||
try {
|
||||
while (!thread.mSuccess && !thread.mFailure) {
|
||||
try {
|
||||
thread.mCondition.await();
|
||||
} catch (InterruptedException e) {
|
||||
// keep waiting
|
||||
}
|
||||
}
|
||||
return thread.mResult;
|
||||
} finally {
|
||||
thread.mLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePassword(AccountManagerResponse response, Account account) {
|
||||
try {
|
||||
mService.updatePassword(response.getIAccountManagerResponse(), account);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void editProperties(AccountManagerResponse response, String accountType) {
|
||||
try {
|
||||
mService.editProperties(response.getIAccountManagerResponse(), accountType);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void getPasswordStrength(AccountManagerResponse response,
|
||||
String accountType, String password) {
|
||||
try {
|
||||
mService.getPasswordStrength(response.getIAccountManagerResponse(),
|
||||
accountType, password);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
|
||||
public void checkUsernameExistence(AccountManagerResponse response,
|
||||
String accountType, String username) {
|
||||
try {
|
||||
mService.checkUsernameExistence(response.getIAccountManagerResponse(),
|
||||
accountType, username);
|
||||
} catch (RemoteException e) {
|
||||
// if this happens the entire runtime will restart
|
||||
}
|
||||
}
|
||||
}
|
||||
32
core/java/android/accounts/AccountManagerResponse.java
Normal file
32
core/java/android/accounts/AccountManagerResponse.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.accounts;
|
||||
|
||||
/**
|
||||
* Object that wraps calls to an {@link IAccountManagerResponse} object.
|
||||
* TODO: this interface is still in flux
|
||||
*/
|
||||
public class AccountManagerResponse {
|
||||
private IAccountManagerResponse mResponse;
|
||||
|
||||
public AccountManagerResponse(IAccountManagerResponse accountManagerResponse) {
|
||||
mResponse = accountManagerResponse;
|
||||
}
|
||||
|
||||
public IAccountManagerResponse getIAccountManagerResponse() {
|
||||
return mResponse;
|
||||
}
|
||||
}
|
||||
901
core/java/android/accounts/AccountManagerService.java
Normal file
901
core/java/android/accounts/AccountManagerService.java
Normal file
@@ -0,0 +1,901 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.*;
|
||||
import android.content.*;
|
||||
import android.database.sqlite.*;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.util.Log;
|
||||
import android.text.TextUtils;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
import com.android.internal.telephony.TelephonyIntents;
|
||||
|
||||
/**
|
||||
* A system service that provides account, password, and authtoken management for all
|
||||
* accounts on the device. Some of these calls are implemented with the help of the corresponding
|
||||
* {@link IAccountAuthenticator} services. This service is not accessed by users directly,
|
||||
* instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
|
||||
* AccountManager accountManager =
|
||||
* (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
|
||||
*/
|
||||
public class AccountManagerService extends IAccountManager.Stub {
|
||||
private static final String TAG = "AccountManagerService";
|
||||
|
||||
private static final int TIMEOUT_DELAY_MS = 1000 * 60;
|
||||
private static final String DATABASE_NAME = "accounts.db";
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private HandlerThread mMessageThread;
|
||||
private final MessageHandler mMessageHandler;
|
||||
|
||||
// Messages that can be sent on mHandler
|
||||
private static final int MESSAGE_TIMED_OUT = 3;
|
||||
private static final int MESSAGE_CONNECTED = 7;
|
||||
private static final int MESSAGE_DISCONNECTED = 8;
|
||||
|
||||
private final AccountAuthenticatorCache mAuthenticatorCache;
|
||||
private final AuthenticatorBindHelper mBindHelper;
|
||||
public final HashMap<AuthTokenKey, String> mAuthTokenCache = Maps.newHashMap();
|
||||
private final DatabaseHelper mOpenHelper;
|
||||
private final SimWatcher mSimWatcher;
|
||||
|
||||
private static final String TABLE_ACCOUNTS = "accounts";
|
||||
private static final String ACCOUNTS_ID = "_id";
|
||||
private static final String ACCOUNTS_NAME = "name";
|
||||
private static final String ACCOUNTS_TYPE = "type";
|
||||
private static final String ACCOUNTS_PASSWORD = "password";
|
||||
|
||||
private static final String TABLE_AUTHTOKENS = "authtokens";
|
||||
private static final String AUTHTOKENS_ID = "_id";
|
||||
private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
|
||||
private static final String AUTHTOKENS_TYPE = "type";
|
||||
private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
|
||||
|
||||
private static final String TABLE_EXTRAS = "extras";
|
||||
private static final String EXTRAS_ID = "_id";
|
||||
private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
|
||||
private static final String EXTRAS_KEY = "key";
|
||||
private static final String EXTRAS_VALUE = "value";
|
||||
|
||||
private static final String TABLE_META = "meta";
|
||||
private static final String META_KEY = "key";
|
||||
private static final String META_VALUE = "value";
|
||||
|
||||
private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
|
||||
new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
|
||||
private static final Intent ACCOUNTS_CHANGED_INTENT =
|
||||
new Intent(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION);
|
||||
|
||||
public class AuthTokenKey {
|
||||
public final Account mAccount;
|
||||
public final String mAuthTokenType;
|
||||
private final int mHashCode;
|
||||
|
||||
public AuthTokenKey(Account account, String authTokenType) {
|
||||
mAccount = account;
|
||||
mAuthTokenType = authTokenType;
|
||||
mHashCode = computeHashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof AuthTokenKey)) {
|
||||
return false;
|
||||
}
|
||||
AuthTokenKey other = (AuthTokenKey)o;
|
||||
if (!mAccount.equals(other.mAccount)) {
|
||||
return false;
|
||||
}
|
||||
return (mAuthTokenType == null)
|
||||
? other.mAuthTokenType == null
|
||||
: mAuthTokenType.equals(other.mAuthTokenType);
|
||||
}
|
||||
|
||||
private int computeHashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + mAccount.hashCode();
|
||||
result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return mHashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public AccountManagerService(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mOpenHelper = new DatabaseHelper(mContext);
|
||||
|
||||
mMessageThread = new HandlerThread("AccountManagerService");
|
||||
mMessageThread.start();
|
||||
mMessageHandler = new MessageHandler(mMessageThread.getLooper());
|
||||
|
||||
mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
|
||||
mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
|
||||
MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
|
||||
|
||||
mSimWatcher = new SimWatcher(mContext);
|
||||
}
|
||||
|
||||
public String getPassword(Account account) throws RemoteException {
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
|
||||
ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
|
||||
new String[]{account.mName, account.mType}, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
return cursor.getString(0);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserData(Account account, String key) throws RemoteException {
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
long accountId = getAccountId(db, account);
|
||||
if (accountId < 0) {
|
||||
return null;
|
||||
}
|
||||
Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
|
||||
EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
|
||||
new String[]{key}, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
return cursor.getString(0);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
} finally {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public Account[] getAccounts() throws RemoteException {
|
||||
return getAccountsByType(null);
|
||||
}
|
||||
|
||||
public Account[] getAccountsByType(String accountType) throws RemoteException {
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
|
||||
final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
|
||||
final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
|
||||
Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
|
||||
selection, selectionArgs, null, null, null);
|
||||
try {
|
||||
int i = 0;
|
||||
Account[] accounts = new Account[cursor.getCount()];
|
||||
while (cursor.moveToNext()) {
|
||||
accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
|
||||
i++;
|
||||
}
|
||||
return accounts;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addAccount(Account account, String password, Bundle extras)
|
||||
throws RemoteException {
|
||||
// fails if the account already exists
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
long numMatches = DatabaseUtils.longForQuery(db,
|
||||
"select count(*) from " + TABLE_ACCOUNTS
|
||||
+ " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
|
||||
new String[]{account.mName, account.mType});
|
||||
if (numMatches > 0) {
|
||||
return false;
|
||||
}
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ACCOUNTS_NAME, account.mName);
|
||||
values.put(ACCOUNTS_TYPE, account.mType);
|
||||
values.put(ACCOUNTS_PASSWORD, password);
|
||||
long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
|
||||
if (accountId < 0) {
|
||||
return false;
|
||||
}
|
||||
if (extras != null) {
|
||||
for (String key : extras.keySet()) {
|
||||
final String value = extras.getString(key);
|
||||
if (insertExtra(db, accountId, key, value) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
|
||||
return true;
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(EXTRAS_KEY, key);
|
||||
values.put(EXTRAS_ACCOUNTS_ID, accountId);
|
||||
values.put(EXTRAS_VALUE, value);
|
||||
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
|
||||
}
|
||||
|
||||
public void removeAccount(Account account) throws RemoteException {
|
||||
// clear out matching authtokens from the cache
|
||||
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
|
||||
new String[]{account.mName, account.mType});
|
||||
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
|
||||
}
|
||||
|
||||
public void invalidateAuthToken(String accountType, String authToken) throws RemoteException {
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
invalidateAuthToken(db, accountType, authToken);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
|
||||
Cursor cursor = db.rawQuery(
|
||||
"SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
|
||||
+ ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
|
||||
+ ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
|
||||
+ " FROM " + TABLE_ACCOUNTS
|
||||
+ " JOIN " + TABLE_AUTHTOKENS
|
||||
+ " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
|
||||
+ " = " + AUTHTOKENS_ACCOUNTS_ID
|
||||
+ " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
|
||||
+ TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
|
||||
new String[]{authToken, accountType});
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
long authTokenId = cursor.getLong(0);
|
||||
String accountName = cursor.getString(1);
|
||||
String authTokenType = cursor.getString(2);
|
||||
AuthTokenKey key = new AuthTokenKey(new Account(accountName, accountType),
|
||||
authTokenType);
|
||||
mAuthTokenCache.remove(key);
|
||||
db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
if (saveAuthTokenToDatabase(db, account, type, authToken)) {
|
||||
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
|
||||
db.setTransactionSuccessful();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean saveAuthTokenToDatabase(SQLiteDatabase db, Account account,
|
||||
String type, String authToken) {
|
||||
long accountId = getAccountId(db, account);
|
||||
if (accountId < 0) {
|
||||
return false;
|
||||
}
|
||||
db.delete(TABLE_AUTHTOKENS,
|
||||
AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
|
||||
new String[]{type});
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
|
||||
values.put(AUTHTOKENS_TYPE, type);
|
||||
values.put(AUTHTOKENS_AUTHTOKEN, authToken);
|
||||
return db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0;
|
||||
}
|
||||
|
||||
public String readAuthTokenFromDatabase(Account account, String authTokenType) {
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
long accountId = getAccountId(db, account);
|
||||
if (accountId < 0) {
|
||||
return null;
|
||||
}
|
||||
return getAuthToken(db, accountId, authTokenType);
|
||||
} finally {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public String peekAuthToken(Account account, String authTokenType) throws RemoteException {
|
||||
AuthTokenKey key = new AuthTokenKey(account, authTokenType);
|
||||
if (mAuthTokenCache.containsKey(key)) {
|
||||
return mAuthTokenCache.get(key);
|
||||
}
|
||||
return readAuthTokenFromDatabase(account, authTokenType);
|
||||
}
|
||||
|
||||
public void setAuthToken(Account account, String authTokenType, String authToken)
|
||||
throws RemoteException {
|
||||
cacheAuthToken(account, authTokenType, authToken);
|
||||
}
|
||||
|
||||
public void setPassword(Account account, String password) throws RemoteException {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ACCOUNTS_PASSWORD, password);
|
||||
mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
|
||||
ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
|
||||
new String[]{account.mName, account.mType});
|
||||
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
|
||||
}
|
||||
|
||||
public void clearPassword(Account account) throws RemoteException {
|
||||
setPassword(account, null);
|
||||
}
|
||||
|
||||
public void setUserData(Account account, String key, String value) throws RemoteException {
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
long accountId = getAccountId(db, account);
|
||||
if (accountId < 0) {
|
||||
return;
|
||||
}
|
||||
long extrasId = getExtrasId(db, accountId, key);
|
||||
if (extrasId < 0 ) {
|
||||
extrasId = insertExtra(db, accountId, key, value);
|
||||
if (extrasId < 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(EXTRAS_VALUE, value);
|
||||
if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public void getAuthToken(IAccountManagerResponse response, Account account,
|
||||
String authTokenType, boolean notifyOnAuthFailure) throws RemoteException {
|
||||
// create a new Session
|
||||
Session session = new GetAuthTokenSession(response, account, authTokenType,
|
||||
notifyOnAuthFailure);
|
||||
|
||||
String authToken = getCachedAuthToken(account, authTokenType);
|
||||
if (authToken != null) {
|
||||
session.onStringResult(authToken);
|
||||
return;
|
||||
}
|
||||
|
||||
session.bind();
|
||||
}
|
||||
|
||||
public void addAccountInteractively(IAccountManagerResponse response, String accountType)
|
||||
throws RemoteException {
|
||||
new AddAccountInteractivelySession(response, accountType).bind();
|
||||
}
|
||||
|
||||
public void authenticateAccount(IAccountManagerResponse response, Account account,
|
||||
String password)
|
||||
throws RemoteException {
|
||||
new AuthenticateAccountSession(response, account, password).bind();
|
||||
}
|
||||
|
||||
public void updatePassword(IAccountManagerResponse response, Account account)
|
||||
throws RemoteException {
|
||||
new UpdatePasswordSession(response, account).bind();
|
||||
}
|
||||
|
||||
public void editProperties(IAccountManagerResponse response, String accountType)
|
||||
throws RemoteException {
|
||||
new EditPropertiesSession(response, accountType).bind();
|
||||
}
|
||||
|
||||
public void getPasswordStrength(IAccountManagerResponse response,
|
||||
String accountType, String password) throws RemoteException {
|
||||
new GetPasswordStrengthSession(response, accountType, password).bind();
|
||||
}
|
||||
|
||||
public void checkUsernameExistence(IAccountManagerResponse response,
|
||||
String accountType, String username) throws RemoteException {
|
||||
new CheckUsernameExistenceSession(response, username, accountType).bind();
|
||||
}
|
||||
|
||||
private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
|
||||
if (saveAuthTokenToDatabase(account, authTokenType, authToken)) {
|
||||
final AuthTokenKey key = new AuthTokenKey(account, authTokenType);
|
||||
mAuthTokenCache.put(key, authToken);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String getCachedAuthToken(Account account, String authTokenType) {
|
||||
final AuthTokenKey key = new AuthTokenKey(account, authTokenType);
|
||||
if (!mAuthTokenCache.containsKey(key)) return null;
|
||||
return mAuthTokenCache.get(key);
|
||||
}
|
||||
|
||||
private long getAccountId(SQLiteDatabase db, Account account) {
|
||||
Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
|
||||
"name=? AND type=?", new String[]{account.mName, account.mType}, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
|
||||
Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
|
||||
EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
|
||||
new String[]{key}, null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
|
||||
Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
|
||||
AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
|
||||
new String[]{authTokenType},
|
||||
null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
return cursor.getString(0);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private class Session extends IAccountAuthenticatorResponse.Stub
|
||||
implements AuthenticatorBindHelper.Callback {
|
||||
IAccountManagerResponse mResponse;
|
||||
final String mAccountType;
|
||||
|
||||
IAccountAuthenticator mAuthenticator = null;
|
||||
|
||||
public Session(IAccountManagerResponse response, String accountType) {
|
||||
super();
|
||||
mResponse = response;
|
||||
mAccountType = accountType;
|
||||
}
|
||||
|
||||
IAccountManagerResponse close() {
|
||||
if (mResponse == null) {
|
||||
// this session has already been closed
|
||||
return null;
|
||||
}
|
||||
cancelTimeout();
|
||||
unbind();
|
||||
IAccountManagerResponse response = mResponse;
|
||||
mResponse = null;
|
||||
return response;
|
||||
}
|
||||
|
||||
void bind() {
|
||||
if (!mBindHelper.bind(mAccountType, this)) {
|
||||
onError(6, "bind failure");
|
||||
}
|
||||
}
|
||||
|
||||
private void unbind() {
|
||||
if (mAuthenticator != null) {
|
||||
mAuthenticator = null;
|
||||
mBindHelper.unbind(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleTimeout() {
|
||||
mMessageHandler.sendMessageDelayed(
|
||||
mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
|
||||
}
|
||||
|
||||
public void cancelTimeout() {
|
||||
mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
|
||||
// do the next step
|
||||
}
|
||||
|
||||
public void onDisconnected() {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
onError(3, "disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
public void onTimedOut() {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
onError(4, "timeout");
|
||||
}
|
||||
}
|
||||
|
||||
public void onIntResult(int result) throws RemoteException {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
response.onIntResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void onBooleanResult(boolean result) throws RemoteException {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
response.onBooleanResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void onStringResult(String result) throws RemoteException {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
response.onStringResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
try {
|
||||
response.onError(errorCode, errorMessage);
|
||||
} catch (RemoteException e) {
|
||||
// error while trying to notify user of an error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GetAuthTokenSession extends Session {
|
||||
final Account mAccount;
|
||||
final String mAuthTokenType;
|
||||
final boolean mNotifyOnAuthFailure;
|
||||
|
||||
public GetAuthTokenSession(IAccountManagerResponse response,
|
||||
Account account, String authTokenType, boolean interactive) {
|
||||
super(response, account.mType);
|
||||
mAccount = account;
|
||||
mAuthTokenType = authTokenType;
|
||||
mNotifyOnAuthFailure = interactive;
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.getAuthToken(this, mAccount.mName, mAccount.mType, mAuthTokenType);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
|
||||
public void onStringResult(String result) throws RemoteException {
|
||||
IAccountManagerResponse response = close();
|
||||
if (response != null) {
|
||||
cacheAuthToken(mAccount, mAccountType, result);
|
||||
response.onStringResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
if (mNotifyOnAuthFailure && errorCode == 0 /* TODO: put the real value here */) {
|
||||
// TODO: authentication failed, pop up the notification
|
||||
}
|
||||
super.onError(errorCode, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private class CheckUsernameExistenceSession extends Session {
|
||||
final String mUsername;
|
||||
|
||||
public CheckUsernameExistenceSession(IAccountManagerResponse response,
|
||||
String username, String accountType) {
|
||||
super(response, accountType);
|
||||
mUsername = username;
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.checkUsernameExistence(this, mAccountType, mUsername);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AddAccountInteractivelySession extends Session {
|
||||
|
||||
public AddAccountInteractivelySession(IAccountManagerResponse response,
|
||||
String accountType) {
|
||||
super(response, accountType);
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.addAccount(this, mAccountType);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthenticateAccountSession extends Session {
|
||||
final String mUsername;
|
||||
final String mPassword;
|
||||
|
||||
public AuthenticateAccountSession(IAccountManagerResponse response, Account account,
|
||||
String password) {
|
||||
super(response, account.mType);
|
||||
mUsername = account.mName;
|
||||
mPassword = password;
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.authenticateAccount(this, mUsername, mAccountType, mPassword);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdatePasswordSession extends Session {
|
||||
final String mUsername;
|
||||
|
||||
public UpdatePasswordSession(IAccountManagerResponse response, Account account) {
|
||||
super(response, account.mType);
|
||||
mUsername = account.mName;
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.updatePassword(this, mUsername, mAccountType);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EditPropertiesSession extends Session {
|
||||
public EditPropertiesSession(IAccountManagerResponse response, String accountType) {
|
||||
super(response, accountType);
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.editProperties(this, mAccountType);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GetPasswordStrengthSession extends Session {
|
||||
final String mPassword;
|
||||
|
||||
public GetPasswordStrengthSession(IAccountManagerResponse response,
|
||||
String accountType, String password) {
|
||||
super(response, accountType);
|
||||
mPassword = password;
|
||||
}
|
||||
|
||||
public void onConnected(IBinder service) {
|
||||
super.onConnected(service);
|
||||
|
||||
try {
|
||||
mAuthenticator.getPasswordStrength(this, mAccountType, mPassword);
|
||||
} catch (RemoteException e) {
|
||||
onError(4, "remote exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageHandler extends Handler {
|
||||
MessageHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
if (mBindHelper.handleMessage(msg)) {
|
||||
return;
|
||||
}
|
||||
switch (msg.what) {
|
||||
case MESSAGE_TIMED_OUT:
|
||||
Session session = (Session)msg.obj;
|
||||
session.onTimedOut();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("unhandled message: " + msg.what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DatabaseHelper extends SQLiteOpenHelper {
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
|
||||
+ ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ ACCOUNTS_NAME + " TEXT NOT NULL, "
|
||||
+ ACCOUNTS_TYPE + " TEXT NOT NULL, "
|
||||
+ ACCOUNTS_PASSWORD + " TEXT, "
|
||||
+ "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
|
||||
|
||||
db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
|
||||
+ AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
|
||||
+ AUTHTOKENS_TYPE + " TEXT NOT NULL, "
|
||||
+ AUTHTOKENS_AUTHTOKEN + " TEXT, "
|
||||
+ "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
|
||||
|
||||
db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
|
||||
+ EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ EXTRAS_ACCOUNTS_ID + " INTEGER, "
|
||||
+ EXTRAS_KEY + " TEXT NOT NULL, "
|
||||
+ EXTRAS_VALUE + " TEXT, "
|
||||
+ "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
|
||||
|
||||
db.execSQL("CREATE TABLE " + TABLE_META + " ( "
|
||||
+ META_KEY + " TEXT PRIMARY KEY NOT NULL, "
|
||||
+ META_VALUE + " TEXT)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.e(TAG, "GLS upgrade from version " + oldVersion + " to version " +
|
||||
newVersion + " not supported");
|
||||
|
||||
db.execSQL("DROP TABLE " + TABLE_ACCOUNTS);
|
||||
db.execSQL("DROP TABLE " + TABLE_AUTHTOKENS);
|
||||
db.execSQL("DROP TABLE " + TABLE_EXTRAS);
|
||||
db.execSQL("DROP TABLE " + TABLE_META);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(SQLiteDatabase db) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMetaValue(String key, String value) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(META_KEY, key);
|
||||
values.put(META_VALUE, value);
|
||||
mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
|
||||
}
|
||||
|
||||
private String getMetaValue(String key) {
|
||||
Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
|
||||
new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
|
||||
try {
|
||||
if (c.moveToNext()) {
|
||||
return c.getString(0);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private class SimWatcher extends BroadcastReceiver {
|
||||
public SimWatcher(Context context) {
|
||||
// Re-scan the SIM card when the SIM state changes, and also if
|
||||
// the disk recovers from a full state (we may have failed to handle
|
||||
// things properly while the disk was full).
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
|
||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the IMSI to the one stored in the login service's
|
||||
* database. If they differ, erase all passwords and
|
||||
* authtokens (and store the new IMSI).
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
|
||||
String imsi = ((TelephonyManager) context.getSystemService(
|
||||
Context.TELEPHONY_SERVICE)).getSubscriberId();
|
||||
if (TextUtils.isEmpty(imsi)) return;
|
||||
|
||||
String storedImsi = getMetaValue("imsi");
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
|
||||
}
|
||||
|
||||
if (!imsi.equals(storedImsi) && !"initial".equals(storedImsi)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "wiping all passwords and authtokens");
|
||||
}
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
|
||||
db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
|
||||
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
setMetaValue("imsi", imsi);
|
||||
}
|
||||
}
|
||||
|
||||
public IBinder onBind(Intent intent) {
|
||||
return asBinder();
|
||||
}
|
||||
}
|
||||
@@ -17,16 +17,10 @@
|
||||
package android.accounts;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.database.SQLException;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.os.*;
|
||||
|
||||
/**
|
||||
* A helper class that calls back on the provided
|
||||
@@ -38,55 +32,15 @@ import android.util.Log;
|
||||
* fetch the current list of accounts (that is, when the
|
||||
* AccountMonitor is first created, and when the intent is received).
|
||||
*/
|
||||
public class AccountMonitor extends BroadcastReceiver implements ServiceConnection {
|
||||
public class AccountMonitor extends BroadcastReceiver {
|
||||
private static final String TAG = "AccountMonitor";
|
||||
|
||||
private final Context mContext;
|
||||
private final AccountMonitorListener mListener;
|
||||
private boolean mClosed = false;
|
||||
private int pending = 0;
|
||||
|
||||
// This thread runs in the background and runs the code to update accounts
|
||||
// in the listener.
|
||||
private class AccountUpdater extends Thread {
|
||||
private IBinder mService;
|
||||
|
||||
public AccountUpdater(IBinder service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
IAccountsService accountsService = IAccountsService.Stub.asInterface(mService);
|
||||
String[] accounts = null;
|
||||
do {
|
||||
try {
|
||||
accounts = accountsService.getAccounts();
|
||||
} catch (RemoteException e) {
|
||||
// if the service was killed then the system will restart it and when it does we
|
||||
// will get another onServiceConnected, at which point we will do a notify.
|
||||
Log.w("AccountMonitor", "Remote exception when getting accounts", e);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (AccountMonitor.this) {
|
||||
--pending;
|
||||
if (pending == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
mContext.unbindService(AccountMonitor.this);
|
||||
|
||||
try {
|
||||
mListener.onAccountsUpdated(accounts);
|
||||
} catch (SQLException e) {
|
||||
// Better luck next time. If the problem was disk-full,
|
||||
// the STORAGE_OK intent will re-trigger the update.
|
||||
Log.e("AccountMonitor", "Can't update accounts", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
private volatile Looper mServiceLooper;
|
||||
private volatile NotifierHandler mServiceHandler;
|
||||
|
||||
/**
|
||||
* Initializes the AccountMonitor and initiates a bind to the
|
||||
@@ -110,8 +64,12 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti
|
||||
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // To recover from disk-full.
|
||||
mContext.registerReceiver(this, intentFilter);
|
||||
|
||||
// Send the listener the initial state now.
|
||||
notifyListener();
|
||||
HandlerThread thread = new HandlerThread("AccountMonitorHandlerThread");
|
||||
thread.start();
|
||||
mServiceLooper = thread.getLooper();
|
||||
mServiceHandler = new NotifierHandler(mServiceLooper);
|
||||
|
||||
mServiceHandler.sendEmptyMessage(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,45 +77,15 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti
|
||||
notifyListener();
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
// Create a background thread to update the accounts.
|
||||
new AccountUpdater(service).start();
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
}
|
||||
|
||||
private synchronized void notifyListener() {
|
||||
if (pending == 0) {
|
||||
// initiate the bind
|
||||
if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
|
||||
this, Context.BIND_AUTO_CREATE)) {
|
||||
// This is normal if GLS isn't part of this build.
|
||||
Log.w("AccountMonitor",
|
||||
"Couldn't connect to " +
|
||||
AccountsServiceConstants.SERVICE_INTENT +
|
||||
" (Missing service?)");
|
||||
}
|
||||
} else {
|
||||
// already bound. bindService will not trigger another
|
||||
// call to onServiceConnected, so instead we make sure
|
||||
// that the existing background thread will call
|
||||
// getAccounts() after this function returns, by
|
||||
// incrementing pending.
|
||||
//
|
||||
// Yes, this else clause contains only a comment.
|
||||
AccountManager accountManager =
|
||||
(AccountManager)mContext.getSystemService(Context.ACCOUNT_SERVICE);
|
||||
Account[] accounts = accountManager.blockingGetAccounts();
|
||||
String[] accountNames = new String[accounts.length];
|
||||
for (int i = 0; i < accounts.length; i++) {
|
||||
accountNames[i] = accounts[i].mName;
|
||||
}
|
||||
++pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* calls close()
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
close();
|
||||
super.finalize();
|
||||
mListener.onAccountsUpdated(accountNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,4 +99,14 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti
|
||||
mClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class NotifierHandler extends Handler {
|
||||
public NotifierHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
notifyListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
172
core/java/android/accounts/AuthenticatorBindHelper.java
Normal file
172
core/java/android/accounts/AuthenticatorBindHelper.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
/**
|
||||
* A helper object that simplifies binding to Account Authenticators. It uses the
|
||||
* {@link AccountAuthenticatorCache} to find the component name of the authenticators,
|
||||
* allowing the user to bind by account name. It also allows multiple, simultaneous binds
|
||||
* to the same authenticator, with each bind call guaranteed to return either
|
||||
* {@link Callback#onConnected} or {@link Callback#onDisconnected} if the bind() call
|
||||
* itself succeeds, even if the authenticator is already bound internally.
|
||||
*/
|
||||
public class AuthenticatorBindHelper {
|
||||
final private Handler mHandler;
|
||||
final private Context mContext;
|
||||
final private int mMessageWhatConnected;
|
||||
final private int mMessageWhatDisconnected;
|
||||
final private Map<String, MyServiceConnection> mServiceConnections = Maps.newHashMap();
|
||||
final private Map<String, ArrayList<Callback>> mServiceUsers = Maps.newHashMap();
|
||||
final private AccountAuthenticatorCache mAuthenticatorCache;
|
||||
|
||||
public AuthenticatorBindHelper(Context context,
|
||||
AccountAuthenticatorCache authenticatorCache, Handler handler,
|
||||
int messageWhatConnected, int messageWhatDisconnected) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mAuthenticatorCache = authenticatorCache;
|
||||
mMessageWhatConnected = messageWhatConnected;
|
||||
mMessageWhatDisconnected = messageWhatDisconnected;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onConnected(IBinder service);
|
||||
void onDisconnected();
|
||||
}
|
||||
|
||||
public boolean bind(String authenticatorType, Callback callback) {
|
||||
// if the authenticator is connecting or connected then return true
|
||||
synchronized (mServiceConnections) {
|
||||
if (mServiceConnections.containsKey(authenticatorType)) {
|
||||
mServiceUsers.get(authenticatorType).add(callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise find the component name for the authenticator and initiate a bind
|
||||
// if no authenticator or the bind fails then return false, otherwise return true
|
||||
AccountAuthenticatorCache.AuthenticatorInfo authenticatorInfo =
|
||||
mAuthenticatorCache.getAuthenticatorInfo(authenticatorType);
|
||||
if (authenticatorInfo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MyServiceConnection connection = new MyServiceConnection(authenticatorType);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("android.accounts.AccountAuthenticator");
|
||||
intent.setComponent(authenticatorInfo.mComponentName);
|
||||
if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mServiceConnections.put(authenticatorType, connection);
|
||||
mServiceUsers.put(authenticatorType, Lists.newArrayList(callback));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void unbind(Callback callbackToUnbind) {
|
||||
synchronized (mServiceConnections) {
|
||||
for (Map.Entry<String, ArrayList<Callback>> entry : mServiceUsers.entrySet()) {
|
||||
final String authenticatorType = entry.getKey();
|
||||
final ArrayList<Callback> serviceUsers = entry.getValue();
|
||||
for (Callback callback : serviceUsers) {
|
||||
if (callback == callbackToUnbind) {
|
||||
serviceUsers.remove(callbackToUnbind);
|
||||
if (serviceUsers.isEmpty()) {
|
||||
unbindFromService(authenticatorType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unbindFromService(String authenticatorType) {
|
||||
mContext.unbindService(mServiceConnections.get(authenticatorType));
|
||||
mServiceUsers.remove(authenticatorType);
|
||||
mServiceConnections.remove(authenticatorType);
|
||||
}
|
||||
|
||||
private class ConnectedMessagePayload {
|
||||
public final IBinder mService;
|
||||
public final Callback mCallback;
|
||||
public ConnectedMessagePayload(IBinder service, Callback callback) {
|
||||
mService = service;
|
||||
mCallback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyServiceConnection implements ServiceConnection {
|
||||
final private String mAuthenticatorType;
|
||||
|
||||
public MyServiceConnection(String authenticatorType) {
|
||||
mAuthenticatorType = authenticatorType;
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
// post a message for each service user to tell them that the service is connected
|
||||
synchronized (mServiceConnections) {
|
||||
for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
|
||||
final ConnectedMessagePayload payload =
|
||||
new ConnectedMessagePayload(service, callback);
|
||||
mHandler.obtainMessage(mMessageWhatConnected, payload).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
// post a message for each service user to tell them that the service is disconnected,
|
||||
// and unbind from the service.
|
||||
synchronized (mServiceConnections) {
|
||||
for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
|
||||
mHandler.obtainMessage(mMessageWhatDisconnected, callback).sendToTarget();
|
||||
}
|
||||
unbindFromService(mAuthenticatorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean handleMessage(Message message) {
|
||||
if (message.what == mMessageWhatConnected) {
|
||||
ConnectedMessagePayload payload = (ConnectedMessagePayload)message.obj;
|
||||
payload.mCallback.onConnected(payload.mService);
|
||||
return true;
|
||||
} else if (message.what == mMessageWhatDisconnected) {
|
||||
Callback callback = (Callback)message.obj;
|
||||
callback.onDisconnected();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
core/java/android/accounts/IAccountAuthenticator.aidl
Normal file
63
core/java/android/accounts/IAccountAuthenticator.aidl
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.accounts.IAccountAuthenticatorResponse;
|
||||
|
||||
/**
|
||||
* Service that allows the interaction with an authentication server.
|
||||
*/
|
||||
oneway interface IAccountAuthenticator {
|
||||
/**
|
||||
* prompts the user for account information and adds the result to the IAccountManager
|
||||
*/
|
||||
void addAccount(in IAccountAuthenticatorResponse response, String accountType);
|
||||
|
||||
/**
|
||||
* prompts the user for the credentials of the account
|
||||
*/
|
||||
void authenticateAccount(in IAccountAuthenticatorResponse response, String name,
|
||||
String type, String password);
|
||||
|
||||
/**
|
||||
* gets the password by either prompting the user or querying the IAccountManager
|
||||
*/
|
||||
void getAuthToken(in IAccountAuthenticatorResponse response,
|
||||
String name, String type, String authTokenType);
|
||||
|
||||
/**
|
||||
* does local analysis or uses a service in the cloud
|
||||
*/
|
||||
void getPasswordStrength(in IAccountAuthenticatorResponse response,
|
||||
String accountType, String password);
|
||||
|
||||
/**
|
||||
* checks with the login service in the cloud
|
||||
*/
|
||||
void checkUsernameExistence(in IAccountAuthenticatorResponse response,
|
||||
String accountType, String username);
|
||||
|
||||
/**
|
||||
* prompts the user for a new password and writes it to the IAccountManager
|
||||
*/
|
||||
void updatePassword(in IAccountAuthenticatorResponse response, String name, String type);
|
||||
|
||||
/**
|
||||
* launches an activity that lets the user edit and set the properties for an authenticator
|
||||
*/
|
||||
void editProperties(in IAccountAuthenticatorResponse response, String accountType);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* The interface used to return responses from an {@link IAccountAuthenticator}
|
||||
*/
|
||||
oneway interface IAccountAuthenticatorResponse {
|
||||
void onIntResult(int result);
|
||||
void onBooleanResult(boolean result);
|
||||
void onStringResult(String result);
|
||||
void onError(int errorCode, String errorMessage);
|
||||
}
|
||||
55
core/java/android/accounts/IAccountManager.aidl
Normal file
55
core/java/android/accounts/IAccountManager.aidl
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
import android.accounts.IAccountManagerResponse;
|
||||
import android.accounts.Account;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Central application service that provides account management.
|
||||
*/
|
||||
interface IAccountManager {
|
||||
String getPassword(in Account account);
|
||||
String getUserData(in Account account, String key);
|
||||
Account[] getAccounts();
|
||||
Account[] getAccountsByType(String accountType);
|
||||
boolean addAccount(in Account account, String password, in Bundle extras);
|
||||
void removeAccount(in Account account);
|
||||
void invalidateAuthToken(String accountType, String authToken);
|
||||
String peekAuthToken(in Account account, String authTokenType);
|
||||
void setAuthToken(in Account account, String authTokenType, String authToken);
|
||||
void setPassword(in Account account, String password);
|
||||
void clearPassword(in Account account);
|
||||
void setUserData(in Account account, String key, String value);
|
||||
|
||||
// interactive
|
||||
|
||||
void getAuthToken(in IAccountManagerResponse response, in Account account, String authTokenType,
|
||||
boolean notifyOnAuthFailure);
|
||||
void addAccountInteractively(in IAccountManagerResponse response, String accountType);
|
||||
void authenticateAccount(in IAccountManagerResponse response, in Account account,
|
||||
String password);
|
||||
void updatePassword(in IAccountManagerResponse response, in Account account);
|
||||
void editProperties(in IAccountManagerResponse response, String accountType);
|
||||
|
||||
// not interactive
|
||||
void getPasswordStrength(in IAccountManagerResponse response, String accountType,
|
||||
String password);
|
||||
void checkUsernameExistence(in IAccountManagerResponse response, String accountType,
|
||||
String username);
|
||||
}
|
||||
27
core/java/android/accounts/IAccountManagerResponse.aidl
Normal file
27
core/java/android/accounts/IAccountManagerResponse.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
/**
|
||||
* The interface used to return responses for asynchronous calls to the {@link IAccountManager}
|
||||
*/
|
||||
oneway interface IAccountManagerResponse {
|
||||
void onStringResult(String value);
|
||||
void onIntResult(int value);
|
||||
void onBooleanResult(boolean value);
|
||||
void onError(int errorCode, String errorMessage);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.accounts;
|
||||
|
||||
/**
|
||||
* Central application service that allows querying the list of accounts.
|
||||
*/
|
||||
interface IAccountsService {
|
||||
/**
|
||||
* Gets the list of Accounts the user has previously logged
|
||||
* in to. Accounts are of the form "username@domain".
|
||||
* <p>
|
||||
* This method will return an empty array if the device doesn't
|
||||
* know about any accounts (yet).
|
||||
*
|
||||
* @return The accounts. The array will be zero-length if the
|
||||
* AccountsService doesn't know about any accounts yet.
|
||||
*/
|
||||
String[] getAccounts();
|
||||
|
||||
/**
|
||||
* This is an interim solution for bypassing a forgotten gesture on the
|
||||
* unlock screen (it is hidden, please make sure it stays this way!). This
|
||||
* will be *removed* when the unlock screen design supports additional
|
||||
* authenticators.
|
||||
* <p>
|
||||
* The user will be presented with username and password fields that are
|
||||
* called as parameters to this method. If true is returned, the user is
|
||||
* able to define a new gesture and get back into the system. If false, the
|
||||
* user can try again.
|
||||
*
|
||||
* @param username The username entered.
|
||||
* @param password The password entered.
|
||||
* @return Whether to allow the user to bypass the lock screen and define a
|
||||
* new gesture.
|
||||
* @hide (The package is already hidden, but just in case someone
|
||||
* unhides that, this should not be revealed.)
|
||||
*/
|
||||
boolean shouldUnlock(String username, String password);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<body>
|
||||
|
||||
{@hide}
|
||||
|
||||
</body>
|
||||
@@ -88,6 +88,8 @@ import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.WindowManagerImpl;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.IAccountManager;
|
||||
|
||||
import com.android.internal.policy.PolicyManager;
|
||||
|
||||
@@ -150,6 +152,7 @@ class ApplicationContext extends Context {
|
||||
private final static boolean DEBUG_ICONS = false;
|
||||
|
||||
private static final Object sSync = new Object();
|
||||
private static AccountManager sAccountManager;
|
||||
private static AlarmManager sAlarmManager;
|
||||
private static PowerManager sPowerManager;
|
||||
private static ConnectivityManager sConnectivityManager;
|
||||
@@ -881,6 +884,8 @@ class ApplicationContext extends Context {
|
||||
return getActivityManager();
|
||||
} else if (ALARM_SERVICE.equals(name)) {
|
||||
return getAlarmManager();
|
||||
} else if (ACCOUNT_SERVICE.equals(name)) {
|
||||
return getAccountManager();
|
||||
} else if (POWER_SERVICE.equals(name)) {
|
||||
return getPowerManager();
|
||||
} else if (CONNECTIVITY_SERVICE.equals(name)) {
|
||||
@@ -921,6 +926,17 @@ class ApplicationContext extends Context {
|
||||
return null;
|
||||
}
|
||||
|
||||
private AccountManager getAccountManager() {
|
||||
synchronized (sSync) {
|
||||
if (sAccountManager == null) {
|
||||
IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
|
||||
IAccountManager service = IAccountManager.Stub.asInterface(b);
|
||||
sAccountManager = new AccountManager(this, service);
|
||||
}
|
||||
}
|
||||
return sAccountManager;
|
||||
}
|
||||
|
||||
private ActivityManager getActivityManager() {
|
||||
synchronized (mSync) {
|
||||
if (mActivityManager == null) {
|
||||
|
||||
@@ -1095,6 +1095,16 @@ public abstract class Context {
|
||||
* @see android.view.LayoutInflater
|
||||
*/
|
||||
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.accounts.AccountManager} for receiving intents at a
|
||||
* time of your choosing.
|
||||
* TODO STOPSHIP perform a final review of the the account apis before shipping
|
||||
*
|
||||
* @see #getSystemService
|
||||
* @see android.accounts.AccountManager
|
||||
*/
|
||||
public static final String ACCOUNT_SERVICE = "account";
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.app.ActivityManager} for interacting with the global
|
||||
|
||||
@@ -181,6 +181,47 @@ class SyncManager {
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!mFactoryTest) {
|
||||
AccountMonitorListener listener = new AccountMonitorListener() {
|
||||
public void onAccountsUpdated(String[] accounts) {
|
||||
final boolean hadAccountsAlready = mAccounts != null;
|
||||
// copy the accounts into a new array and change mAccounts to point to it
|
||||
String[] newAccounts = new String[accounts.length];
|
||||
System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
|
||||
mAccounts = newAccounts;
|
||||
|
||||
// if a sync is in progress yet it is no longer in the accounts list,
|
||||
// cancel it
|
||||
ActiveSyncContext activeSyncContext = mActiveSyncContext;
|
||||
if (activeSyncContext != null) {
|
||||
if (!ArrayUtils.contains(newAccounts,
|
||||
activeSyncContext.mSyncOperation.account)) {
|
||||
Log.d(TAG, "canceling sync since the account has been removed");
|
||||
sendSyncFinishedOrCanceledMessage(activeSyncContext,
|
||||
null /* no result since this is a cancel */);
|
||||
}
|
||||
}
|
||||
|
||||
// we must do this since we don't bother scheduling alarms when
|
||||
// the accounts are not set yet
|
||||
sendCheckAlarmsMessage();
|
||||
|
||||
mSyncStorageEngine.doDatabaseCleanup(accounts);
|
||||
|
||||
if (hadAccountsAlready && mAccounts.length > 0) {
|
||||
// request a sync so that if the password was changed we will
|
||||
// retry any sync that failed when it was wrong
|
||||
startSync(null /* all providers */, null /* no extras */);
|
||||
}
|
||||
}
|
||||
};
|
||||
mAccountMonitor = new AccountMonitor(context, listener);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mConnectivityIntentReceiver =
|
||||
new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@@ -241,7 +282,11 @@ class SyncManager {
|
||||
|
||||
private static final String SYNCMANAGER_PREFS_FILENAME = "/data/system/syncmanager.prefs";
|
||||
|
||||
private final boolean mFactoryTest;
|
||||
|
||||
public SyncManager(Context context, boolean factoryTest) {
|
||||
mFactoryTest = factoryTest;
|
||||
|
||||
// Initialize the SyncStorageEngine first, before registering observers
|
||||
// and creating threads and so on; it may fail if the disk is full.
|
||||
SyncStorageEngine.init(context);
|
||||
@@ -265,6 +310,9 @@ class SyncManager {
|
||||
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
|
||||
|
||||
intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
|
||||
context.registerReceiver(mBootCompletedReceiver, intentFilter);
|
||||
|
||||
intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
|
||||
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
|
||||
context.registerReceiver(mStorageIntentReceiver, intentFilter);
|
||||
@@ -288,42 +336,6 @@ class SyncManager {
|
||||
mHandleAlarmWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
HANDLE_SYNC_ALARM_WAKE_LOCK);
|
||||
mHandleAlarmWakeLock.setReferenceCounted(false);
|
||||
|
||||
if (!factoryTest) {
|
||||
AccountMonitorListener listener = new AccountMonitorListener() {
|
||||
public void onAccountsUpdated(String[] accounts) {
|
||||
final boolean hadAccountsAlready = mAccounts != null;
|
||||
// copy the accounts into a new array and change mAccounts to point to it
|
||||
String[] newAccounts = new String[accounts.length];
|
||||
System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
|
||||
mAccounts = newAccounts;
|
||||
|
||||
// if a sync is in progress yet it is no longer in the accounts list, cancel it
|
||||
ActiveSyncContext activeSyncContext = mActiveSyncContext;
|
||||
if (activeSyncContext != null) {
|
||||
if (!ArrayUtils.contains(newAccounts,
|
||||
activeSyncContext.mSyncOperation.account)) {
|
||||
Log.d(TAG, "canceling sync since the account has been removed");
|
||||
sendSyncFinishedOrCanceledMessage(activeSyncContext,
|
||||
null /* no result since this is a cancel */);
|
||||
}
|
||||
}
|
||||
|
||||
// we must do this since we don't bother scheduling alarms when
|
||||
// the accounts are not set yet
|
||||
sendCheckAlarmsMessage();
|
||||
|
||||
mSyncStorageEngine.doDatabaseCleanup(accounts);
|
||||
|
||||
if (hadAccountsAlready && mAccounts.length > 0) {
|
||||
// request a sync so that if the password was changed we will retry any sync
|
||||
// that failed when it was wrong
|
||||
startSync(null /* all providers */, null /* no extras */);
|
||||
}
|
||||
}
|
||||
};
|
||||
mAccountMonitor = new AccountMonitor(context, listener);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initializeSyncPoll() {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<!-- Permissions for things that cost money -->
|
||||
<!-- ====================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that can be used to make the user spend money
|
||||
without their direct involvement. For example, this is the group
|
||||
for permissions that allow you to directly place phone calls,
|
||||
@@ -54,7 +54,7 @@
|
||||
<!-- Permissions for accessing messages -->
|
||||
<!-- ================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that allow an application to send messages
|
||||
on behalf of the user or intercept messages being received by the
|
||||
user. This is primarily intended for SMS/MMS messaging, such as
|
||||
@@ -104,7 +104,7 @@
|
||||
<!-- Permissions for accessing personal info (contacts and calendar) -->
|
||||
<!-- =============================================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that provide access to the user's private data,
|
||||
such as contacts, calendar events, e-mail messages, etc. This includes
|
||||
both reading and writing of this data (which should generally be
|
||||
@@ -158,8 +158,8 @@
|
||||
android:description="@string/permdesc_writeCalendar" />
|
||||
|
||||
<!-- Allows an application to read the user dictionary. This should
|
||||
really only be required by an IME, or a dictionary editor like
|
||||
the Settings app.
|
||||
really only be required by an IME, or a dictionary editor like
|
||||
the Settings app.
|
||||
@hide Pending API council approval -->
|
||||
<permission android:name="android.permission.READ_USER_DICTIONARY"
|
||||
android:permissionGroup="android.permission-group.PERSONAL_INFO"
|
||||
@@ -179,7 +179,7 @@
|
||||
<!-- Permissions for accessing location info -->
|
||||
<!-- ======================================= -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that allow access to the user's current
|
||||
location. -->
|
||||
<permission-group android:name="android.permission-group.LOCATION"
|
||||
@@ -216,7 +216,7 @@
|
||||
<!-- Permissions for accessing networks -->
|
||||
<!-- ======================================= -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that provide access to networking services. The
|
||||
main permission here is internet access, but this is also an
|
||||
appropriate group for accessing or modifying any network configuration
|
||||
@@ -257,7 +257,7 @@
|
||||
<!-- Permissions for accessing accounts -->
|
||||
<!-- ================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Permissions for direct access to Google accounts.
|
||||
Note that while right now this is only used for Google accounts,
|
||||
we expect in the future to have a more general account management
|
||||
@@ -278,7 +278,7 @@
|
||||
<!-- Permissions for accessing hardware -->
|
||||
<!-- ================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that provide direct access to the hardware on
|
||||
the device. This includes audio, the camera, vibrator, etc. -->
|
||||
<permission-group android:name="android.permission-group.HARDWARE_CONTROLS"
|
||||
@@ -331,7 +331,7 @@
|
||||
<!-- Permissions associated with telephony state -->
|
||||
<!-- =========================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Used for permissions that are associated with accessing and modifyign
|
||||
telephony state: intercepting outgoing calls, reading
|
||||
and modifying the phone state. Note that
|
||||
@@ -368,7 +368,7 @@
|
||||
<!-- Permissions for low-level system interaction -->
|
||||
<!-- ============================================ -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Group of permissions that are related to system APIs. Many
|
||||
of these are not permissions the user will be expected to understand,
|
||||
and such permissions should generally be marked as "normal" protection
|
||||
@@ -592,7 +592,7 @@
|
||||
android:description="@string/permdesc_writeApnSettings"
|
||||
android:label="@string/permlab_writeApnSettings" />
|
||||
|
||||
<!-- Allows an application to allow access the subscribed feeds
|
||||
<!-- Allows an application to allow access the subscribed feeds
|
||||
ContentProvider. -->
|
||||
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
@@ -604,7 +604,7 @@
|
||||
android:label="@string/permlab_subscribedFeedsWrite"
|
||||
android:description="@string/permdesc_subscribedFeedsWrite"
|
||||
android:protectionLevel="dangerous" />
|
||||
|
||||
|
||||
<!-- Allows applications to change network connectivity state -->
|
||||
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
@@ -648,7 +648,7 @@
|
||||
<!-- Permissions for special development tools -->
|
||||
<!-- ========================================= -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Group of permissions that are related to development features. These
|
||||
are not permissions that should appear in normal applications; they
|
||||
protect APIs that are intended only to be used for development
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<!-- Inverse hint text color -->
|
||||
<attr name="textColorHintInverse" format="reference|color" />
|
||||
|
||||
|
||||
<!-- Bright text color. Only differentiates based on the disabled state. -->
|
||||
<attr name="textColorPrimaryDisableOnly" format="reference|color" />
|
||||
|
||||
@@ -96,20 +96,20 @@
|
||||
|
||||
<!-- Text color, typeface, size, and style for the text inside of a button. -->
|
||||
<attr name="textAppearanceButton" format="reference" />
|
||||
|
||||
|
||||
<!-- A styled string, specifying the style to be used for showing
|
||||
inline candidate text when composing with an input method. The
|
||||
text itself will be ignored, but the style spans will be applied
|
||||
to the candidate text as it is edited. -->
|
||||
<attr name="candidatesTextStyleSpans" format="reference|string" />
|
||||
|
||||
|
||||
<!-- Drawable to use for check marks -->
|
||||
<attr name="textCheckMark" format="reference" />
|
||||
<attr name="textCheckMarkInverse" format="reference" />
|
||||
|
||||
<!-- Drawable to use for multiple choice indicators-->
|
||||
<attr name="listChoiceIndicatorMultiple" format="reference" />
|
||||
|
||||
|
||||
<!-- Drawable to use for single choice indicators-->
|
||||
<attr name="listChoiceIndicatorSingle" format="reference" />
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
<!-- Gallery styles -->
|
||||
<!-- ============== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- The preferred background for gallery items. This should be set
|
||||
as the background of any Views you provide from the Adapter. -->
|
||||
<attr name="galleryItemBackground" format="reference" />
|
||||
@@ -152,20 +152,20 @@
|
||||
<attr name="listSeparatorTextViewStyle" format="reference" />
|
||||
<!-- The preferred left padding for an expandable list item (for child-specific layouts,
|
||||
use expandableListPreferredChildPaddingLeft). This takes into account
|
||||
the indicator that will be shown to next to the item. -->
|
||||
the indicator that will be shown to next to the item. -->
|
||||
<attr name="expandableListPreferredItemPaddingLeft" format="dimension" />
|
||||
<!-- The preferred left padding for an expandable list item that is a child.
|
||||
If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. -->
|
||||
If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. -->
|
||||
<attr name="expandableListPreferredChildPaddingLeft" format="dimension" />
|
||||
<!-- The preferred left bound for an expandable list item's indicator. For a child-specific
|
||||
indicator, use expandableListPreferredChildIndicatorLeft. -->
|
||||
indicator, use expandableListPreferredChildIndicatorLeft. -->
|
||||
<attr name="expandableListPreferredItemIndicatorLeft" format="dimension" />
|
||||
<!-- The preferred right bound for an expandable list item's indicator. For a child-specific
|
||||
indicator, use expandableListPreferredChildIndicatorRight. -->
|
||||
indicator, use expandableListPreferredChildIndicatorRight. -->
|
||||
<attr name="expandableListPreferredItemIndicatorRight" format="dimension" />
|
||||
<!-- The preferred left bound for an expandable list child's indicator. -->
|
||||
<!-- The preferred left bound for an expandable list child's indicator. -->
|
||||
<attr name="expandableListPreferredChildIndicatorLeft" format="dimension" />
|
||||
<!-- The preferred right bound for an expandable list child's indicator. -->
|
||||
<!-- The preferred right bound for an expandable list child's indicator. -->
|
||||
<attr name="expandableListPreferredChildIndicatorRight" format="dimension" />
|
||||
|
||||
<!-- ============= -->
|
||||
@@ -214,7 +214,7 @@
|
||||
any of the attributes defined by
|
||||
{@link android.R.styleable#WindowAnimation}. -->
|
||||
<attr name="windowAnimationStyle" format="reference" />
|
||||
|
||||
|
||||
<!-- Defines the default soft input state that this window would
|
||||
like when it is displayed. -->
|
||||
<attr name="windowSoftInputMode">
|
||||
@@ -236,7 +236,7 @@
|
||||
<!-- Always make the soft input area visible when this window
|
||||
has input focus. -->
|
||||
<flag name="stateAlwaysVisible" value="5" />
|
||||
|
||||
|
||||
<!-- The window resize/pan adjustment has not been specified,
|
||||
the system will automatically select between resize and pan
|
||||
modes, depending
|
||||
@@ -263,7 +263,7 @@
|
||||
use the window's theme to show a preview of it before your
|
||||
actual instance is shown to the user. -->
|
||||
<attr name="windowDisablePreview" format="boolean" />
|
||||
|
||||
|
||||
<!-- Flag indicating that this window should not be displayed at all.
|
||||
The default value is false; if set to true, and this window is
|
||||
the main window of an Activity, then it will never actually
|
||||
@@ -271,13 +271,13 @@
|
||||
must immediately quit without waiting for user interaction,
|
||||
because there will be no such interaction coming. -->
|
||||
<attr name="windowNoDisplay" format="boolean" />
|
||||
|
||||
|
||||
<!-- ============ -->
|
||||
<!-- Alert Dialog styles -->
|
||||
<!-- ============ -->
|
||||
<eat-comment />
|
||||
<attr name="alertDialogStyle" format="reference" />
|
||||
|
||||
|
||||
<!-- ============ -->
|
||||
<!-- Panel styles -->
|
||||
<!-- ============ -->
|
||||
@@ -376,7 +376,7 @@
|
||||
<!-- Preference styles -->
|
||||
<!-- =================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Default style for PreferenceScreen. -->
|
||||
<attr name="preferenceScreenStyle" format="reference" />
|
||||
<!-- Default style for PreferenceCategory. -->
|
||||
@@ -397,7 +397,7 @@
|
||||
<attr name="ringtonePreferenceStyle" format="reference" />
|
||||
<!-- The preference layout that has the child/tabbed effect. -->
|
||||
<attr name="preferenceLayoutChild" format="reference" />
|
||||
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
<!-- **************************************************************** -->
|
||||
@@ -415,7 +415,7 @@
|
||||
</ul>
|
||||
-->
|
||||
<attr name="textSize" format="dimension" />
|
||||
|
||||
|
||||
<!-- Default text typeface. -->
|
||||
<attr name="typeface">
|
||||
<enum name="normal" value="0" />
|
||||
@@ -423,26 +423,26 @@
|
||||
<enum name="serif" value="2" />
|
||||
<enum name="monospace" value="3" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- Default text typeface style. -->
|
||||
<attr name="textStyle">
|
||||
<flag name="normal" value="0" />
|
||||
<flag name="bold" value="1" />
|
||||
<flag name="italic" value="2" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- Color of text (usually same as colorForeground). -->
|
||||
<attr name="textColor" format="reference|color" />
|
||||
|
||||
|
||||
<!-- Color of highlighted text. -->
|
||||
<attr name="textColorHighlight" format="reference|color" />
|
||||
|
||||
|
||||
<!-- Color of hint text (displayed when the field is empty). -->
|
||||
<attr name="textColorHint" format="reference|color" />
|
||||
|
||||
|
||||
<!-- Color of link text (URLs). -->
|
||||
<attr name="textColorLink" format="reference|color" />
|
||||
|
||||
|
||||
<!-- Where to ellipsize text. -->
|
||||
<attr name="ellipsize">
|
||||
<enum name="none" value="0" />
|
||||
@@ -451,7 +451,7 @@
|
||||
<enum name="end" value="3" />
|
||||
<enum name="marquee" value="4" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- The type of data being placed in a text field, used to help an
|
||||
input method decide how to let the user enter text. The constants
|
||||
here correspond to those defined by
|
||||
@@ -658,7 +658,7 @@
|
||||
<attr name="x" format="dimension" />
|
||||
<!-- A coordinate in the Y dimension. -->
|
||||
<attr name="y" format="dimension" />
|
||||
|
||||
|
||||
<!-- Specifies how to place an object, both
|
||||
its x and y axis, within a larger containing object. -->
|
||||
<attr name="gravity">
|
||||
@@ -764,11 +764,11 @@
|
||||
<!-- ========================== -->
|
||||
<eat-comment />
|
||||
|
||||
<!-- This enum provides the same keycode values as can be found in
|
||||
<!-- This enum provides the same keycode values as can be found in
|
||||
{@link android.view.KeyEvent} -->
|
||||
<attr name="keycode">
|
||||
<enum name="KEYCODE_UNKNOWN" value="0" />
|
||||
<enum name="KEYCODE_SOFT_LEFT" value="1" />
|
||||
<enum name="KEYCODE_SOFT_LEFT" value="1" />
|
||||
<enum name="KEYCODE_SOFT_RIGHT" value="2" />
|
||||
<enum name="KEYCODE_HOME" value="3" />
|
||||
<enum name="KEYCODE_BACK" value="4" />
|
||||
@@ -901,7 +901,7 @@
|
||||
<attr name="bottomMedium" format="reference|color" />
|
||||
<attr name="centerMedium" format="reference|color" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- Window animation class attributes. -->
|
||||
<declare-styleable name="WindowAnimation">
|
||||
<!-- The animation used when a window is being added. -->
|
||||
@@ -945,7 +945,7 @@
|
||||
allows you to later retrieve the view
|
||||
with <code>findViewById(R.id.my_id)</code>. -->
|
||||
<attr name="id" format="reference" />
|
||||
|
||||
|
||||
<!-- Supply a tag for this view containing a String, to be retrieved
|
||||
later with {@link android.view.View#getTag View.getTag()} or
|
||||
searched for with {@link android.view.View#findViewWithTag
|
||||
@@ -953,7 +953,7 @@
|
||||
IDs (through the android:id attribute) instead of tags because
|
||||
they are faster and allow for compile-time type checking. -->
|
||||
<attr name="tag" format="string" />
|
||||
|
||||
|
||||
<!-- The initial horizontal scroll offset, in pixels.-->
|
||||
<attr name="scrollX" format="dimension" />
|
||||
|
||||
@@ -967,7 +967,7 @@
|
||||
<attr name="background" format="reference|color" />
|
||||
|
||||
<!-- Sets the padding, in pixels, of all four edges. Padding is defined as
|
||||
space between the edges of the view and the view's content. A views size
|
||||
space between the edges of the view and the view's content. A views size
|
||||
will include it's padding. If a {@link android.R.attr#background}
|
||||
is provided, the padding will initially be set to that (0 if the
|
||||
drawable does not have padding). Explicitly setting a padding value
|
||||
@@ -1022,12 +1022,12 @@
|
||||
</attr>
|
||||
|
||||
<!-- Controls the scrollbar style and position. The scrollbars can be overlaid or
|
||||
inset. When inset, they add to the padding of the view. And the
|
||||
scrollbars can be drawn inside the padding area or on the edge of
|
||||
the view. For example, if a view has a background drawable and you
|
||||
want to draw the scrollbars inside the padding specified by the
|
||||
drawable, you can use insideOverlay or insideInset. If you want them
|
||||
to appear at the edge of the view, ignoring the padding, then you can
|
||||
inset. When inset, they add to the padding of the view. And the
|
||||
scrollbars can be drawn inside the padding area or on the edge of
|
||||
the view. For example, if a view has a background drawable and you
|
||||
want to draw the scrollbars inside the padding specified by the
|
||||
drawable, you can use insideOverlay or insideInset. If you want them
|
||||
to appear at the edge of the view, ignoring the padding, then you can
|
||||
use outsideOverlay or outsideInset.-->
|
||||
<attr name="scrollbarStyle">
|
||||
<!-- Inside the padding and overlaid -->
|
||||
@@ -1039,14 +1039,14 @@
|
||||
<!-- Edge of the view and inset -->
|
||||
<enum name="outsideInset" value="0x03000000" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- Set this if the view will serve as a scrolling container, meaing
|
||||
that it can be resized to shrink its overall window so that there
|
||||
will be space for an input method. If not set, the default
|
||||
value will be true if "scrollbars" has the vertical scrollbar
|
||||
set, else it will be false. -->
|
||||
<attr name="isScrollContainer" format="boolean" />
|
||||
|
||||
|
||||
<!-- Sets the width of vertical scrollbars and height of horizontal scrollbars. -->
|
||||
<attr name="scrollbarSize" format="dimension" />
|
||||
<!-- Defines the horizontal scrollbar thumb drawable. -->
|
||||
@@ -1108,10 +1108,10 @@
|
||||
|
||||
<!-- Defines whether this view reacts to click events. -->
|
||||
<attr name="clickable" format="boolean" />
|
||||
|
||||
|
||||
<!-- Defines whether this view reacts to long click events. -->
|
||||
<attr name="longClickable" format="boolean" />
|
||||
|
||||
|
||||
<!-- If unset, no state will be saved for this view when it is being
|
||||
frozen. The default is true, allowing the view to be saved
|
||||
(however it also must have an ID assigned to it for its
|
||||
@@ -1119,7 +1119,7 @@
|
||||
state for this view, not for its children which may still
|
||||
be saved. -->
|
||||
<attr name="saveEnabled" format="boolean" />
|
||||
|
||||
|
||||
<!-- Defines the quality of translucent drawing caches. This property is used
|
||||
only when the drawing cache is enabled and translucent. The default value is auto. -->
|
||||
<attr name="drawingCacheQuality">
|
||||
@@ -1137,16 +1137,16 @@
|
||||
<!-- Controls whether the view's window should keep the screen on
|
||||
while visible. -->
|
||||
<attr name="keepScreenOn" format="boolean" />
|
||||
|
||||
|
||||
<!-- When this attribute is set to true, the view gets its drawable state
|
||||
(focused, pressed, etc.) from its direct parent rather than from itself. -->
|
||||
<attr name="duplicateParentState" format="boolean" />
|
||||
|
||||
|
||||
<!-- Defines the minimum height of the view. It is not guaranteed
|
||||
the view will be able to achieve this minimum height (for example,
|
||||
if its parent layout constrains it with less available height). -->
|
||||
<attr name="minHeight" />
|
||||
|
||||
|
||||
<!-- Defines the minimum width of the view. It is not guaranteed
|
||||
the view will be able to achieve this minimum width (for example,
|
||||
if its parent layout constrains it with less available width). -->
|
||||
@@ -1196,7 +1196,7 @@
|
||||
<flag name="animation" value="0x1" />
|
||||
<!-- The drawing cache is persisted after a scroll. -->
|
||||
<flag name="scrolling" value="0x2" />
|
||||
<!-- The drawing cache is always persisted. -->
|
||||
<!-- The drawing cache is always persisted. -->
|
||||
<flag name="all" value="0x3" />
|
||||
</attr>
|
||||
<!-- Defines whether the ViewGroup should always draw its children using their
|
||||
@@ -1308,7 +1308,7 @@
|
||||
method should be considered an option as the default. -->
|
||||
<attr name="isDefault" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- Widget package class attributes -->
|
||||
<!-- =============================== -->
|
||||
@@ -1317,7 +1317,7 @@
|
||||
<declare-styleable name="AbsListView">
|
||||
<!-- Drawable used to indicate the currently selected item in the list. -->
|
||||
<attr name="listSelector" format="color|reference" />
|
||||
<!-- When set to true, the selector will be drawn over the selected item.
|
||||
<!-- When set to true, the selector will be drawn over the selected item.
|
||||
Otherwise the selector is drawn behind the selected item. The default
|
||||
value is false. -->
|
||||
<attr name="drawSelectorOnTop" format="boolean" />
|
||||
@@ -1340,13 +1340,13 @@
|
||||
already visible on screen. -->
|
||||
<enum name="normal" value="1" />
|
||||
<!-- The list will automatically scroll to the bottom, no matter what items
|
||||
are currently visible. -->
|
||||
are currently visible. -->
|
||||
<enum name="alwaysScroll" value="2" />
|
||||
</attr>
|
||||
<!-- Indicates that this list will always be drawn on top of solid, single-color
|
||||
opaque background. This allows the list to optimize drawing. -->
|
||||
<attr name="cacheColorHint" format="color" />
|
||||
<!-- Enables the fast scroll thumb that can be dragged to quickly scroll through
|
||||
<!-- Enables the fast scroll thumb that can be dragged to quickly scroll through
|
||||
the list. -->
|
||||
<attr name="fastScrollEnabled" format="boolean" />
|
||||
<!-- When set to true, the list will use a more refined calculation
|
||||
@@ -1435,7 +1435,7 @@
|
||||
<!-- Defines whether the foreground drawable should be drawn inside the padding.
|
||||
This property is turned on by default. -->
|
||||
<attr name="foregroundInsidePadding" format="boolean" />
|
||||
<!-- Determines whether to measure all children or just those in
|
||||
<!-- Determines whether to measure all children or just those in
|
||||
the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
|
||||
<attr name="measureAllChildren" format="boolean" />
|
||||
</declare-styleable>
|
||||
@@ -1445,14 +1445,14 @@
|
||||
<!-- Indicator shown beside the child View. This can be a stateful Drawable. -->
|
||||
<attr name="childIndicator" format="reference" />
|
||||
<!-- The left bound for an item's indicator. To specify a left bound specific to children,
|
||||
use childIndicatorLeft. -->
|
||||
use childIndicatorLeft. -->
|
||||
<attr name="indicatorLeft" format="dimension" />
|
||||
<!-- The right bound for an item's indicator. To specify a right bound specific to children,
|
||||
use childIndicatorRight. -->
|
||||
use childIndicatorRight. -->
|
||||
<attr name="indicatorRight" format="dimension" />
|
||||
<!-- The left bound for a child's indicator. -->
|
||||
<!-- The left bound for a child's indicator. -->
|
||||
<attr name="childIndicatorLeft" format="dimension" />
|
||||
<!-- The right bound for a child's indicator. -->
|
||||
<!-- The right bound for a child's indicator. -->
|
||||
<attr name="childIndicatorRight" format="dimension" />
|
||||
<!-- Drawable or color that is used as a divider for children. (It will drawn
|
||||
below and above child items.) The height of this will be the same as
|
||||
@@ -1503,10 +1503,10 @@
|
||||
<!-- Set this to true if you want the ImageView to adjust its bounds
|
||||
to preserve the aspect ratio of its drawable. -->
|
||||
<attr name="adjustViewBounds" format="boolean" />
|
||||
<!-- An optional argument to supply a maximum width for this view.
|
||||
<!-- An optional argument to supply a maximum width for this view.
|
||||
See {see android.widget.ImageView#setMaxWidth} for details. -->
|
||||
<attr name="maxWidth" format="dimension" />
|
||||
<!-- An optional argument to supply a maximum height for this view.
|
||||
<!-- An optional argument to supply a maximum height for this view.
|
||||
See {see android.widget.ImageView#setMaxHeight} for details. -->
|
||||
<attr name="maxHeight" format="dimension" />
|
||||
<!-- Set a tinting color for the image -->
|
||||
@@ -1560,9 +1560,9 @@
|
||||
<!-- Height of the divider. Will use the intrinsic height of the divider if this
|
||||
is not specified. -->
|
||||
<attr name="dividerHeight" format="dimension" />
|
||||
<!-- Defines the choice behavior for the List. By default, Lists do not have
|
||||
<!-- Defines the choice behavior for the List. By default, Lists do not have
|
||||
any choice behavior. By setting the choiceMode to singleChoice, the List
|
||||
allows up to one item to be in a chosen state. By setting the choiceMode to
|
||||
allows up to one item to be in a chosen state. By setting the choiceMode to
|
||||
multipleChoice, the list allows any number of items to be chosen. -->
|
||||
<attr name="choiceMode">
|
||||
<!-- Normal list that does not indicate choices -->
|
||||
@@ -1607,7 +1607,7 @@
|
||||
<!-- 'More' icon -->
|
||||
<attr name="moreIcon" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="ProgressBar">
|
||||
<!-- Defines the maximum value the progress can take. -->
|
||||
<attr name="max" format="integer" />
|
||||
@@ -1640,27 +1640,27 @@
|
||||
<attr name="maxWidth" />
|
||||
<attr name="minHeight" format="dimension" />
|
||||
<attr name="maxHeight" />
|
||||
<attr name="interpolator" format="reference" />
|
||||
<attr name="interpolator" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="SeekBar">
|
||||
<!-- Draws the thumb on a seekbar -->
|
||||
<!-- Draws the thumb on a seekbar -->
|
||||
<attr name="thumb" format="reference" />
|
||||
<!-- An offset for the thumb that allows it to extend out of the range of the track. -->
|
||||
<attr name="thumbOffset" format="dimension" />
|
||||
<attr name="thumbOffset" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="RatingBar">
|
||||
<!-- The number of stars (or rating items) to show. -->
|
||||
<attr name="numStars" format="integer" />
|
||||
<!-- The rating to set by default. -->
|
||||
<attr name="rating" format="float" />
|
||||
<!-- The step size of the rating. -->
|
||||
<attr name="stepSize" format="float" />
|
||||
<!-- Whether this rating bar is an indicator (and non-changeable by the user). -->
|
||||
<attr name="isIndicator" format="boolean" />
|
||||
<!-- The number of stars (or rating items) to show. -->
|
||||
<attr name="numStars" format="integer" />
|
||||
<!-- The rating to set by default. -->
|
||||
<attr name="rating" format="float" />
|
||||
<!-- The step size of the rating. -->
|
||||
<attr name="stepSize" format="float" />
|
||||
<!-- Whether this rating bar is an indicator (and non-changeable by the user). -->
|
||||
<attr name="isIndicator" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="RadioGroup">
|
||||
<!-- The id of the child radio button that should be checked by default
|
||||
within this radio group. -->
|
||||
@@ -1682,7 +1682,7 @@
|
||||
indices are ignored. You can shrink all columns by using the
|
||||
value "*" instead. Note that a column can be marked stretchable
|
||||
and shrinkable at the same time. -->
|
||||
<attr name="shrinkColumns" format="string" />
|
||||
<attr name="shrinkColumns" format="string" />
|
||||
<!-- The 0 based index of the columns to collapse. The column indices
|
||||
must be separated by a comma: 1, 2, 5. Illegal and duplicate
|
||||
indices are ignored. -->
|
||||
@@ -1783,7 +1783,7 @@
|
||||
<attr name="minEms" format="integer" min="0" />
|
||||
<!-- Makes the TextView be at least this many pixels wide -->
|
||||
<attr name="minWidth" />
|
||||
<!-- Specifies how to align the text by the view's x and/or y axis
|
||||
<!-- Specifies how to align the text by the view's x and/or y axis
|
||||
when the text is smaller than the view. -->
|
||||
<attr name="gravity" />
|
||||
<!-- Whether the text is allowed to be wider than the view (and
|
||||
@@ -1801,10 +1801,10 @@
|
||||
attribute. (If both singleLine and inputType are supplied,
|
||||
the inputType flags will override the value of singleLine.)
|
||||
{@deprecated This attribute is deprecated and is replaced by the textMultiLine flag
|
||||
in the inputType attribute. Use caution when altering existing layouts, as the
|
||||
default value of singeLine is false (multi-line mode), but if you specify any
|
||||
value for inputType, the default is single-line mode. (If both singleLine and
|
||||
inputType attributes are found, the inputType flags will override the value of
|
||||
in the inputType attribute. Use caution when altering existing layouts, as the
|
||||
default value of singeLine is false (multi-line mode), but if you specify any
|
||||
value for inputType, the default is single-line mode. (If both singleLine and
|
||||
inputType attributes are found, the inputType flags will override the value of
|
||||
singleLine.) } -->
|
||||
<attr name="singleLine" format="boolean" />
|
||||
<!-- {@deprecated Use state_enabled instead.} -->
|
||||
@@ -1908,7 +1908,7 @@
|
||||
<attr name="lineSpacingExtra" format="dimension" />
|
||||
<!-- Extra spacing between lines of text, as a multiplier. -->
|
||||
<attr name="lineSpacingMultiplier" format="float" />
|
||||
<!-- The number of times to repeat the marquee animation. Only applied if the
|
||||
<!-- The number of times to repeat the marquee animation. Only applied if the
|
||||
TextView has marquee enabled. -->
|
||||
<attr name="marqueeRepeatLimit" format="integer">
|
||||
<!-- Indicates that marquee should repeat indefinitely -->
|
||||
@@ -1999,7 +1999,7 @@
|
||||
<!-- The prompt to display when the spinner's dialog is shown. -->
|
||||
<attr name="prompt" format="reference" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="DatePicker">
|
||||
<declare-styleable name="DatePicker">
|
||||
<!-- The first year (inclusive) i.e. 1940 -->
|
||||
<attr name="startYear" format="integer" />
|
||||
<!-- The last year (inclusive) i.e. 2010 -->
|
||||
@@ -2123,7 +2123,7 @@
|
||||
{@link android.graphics.drawable.Drawable#setVisible} -->
|
||||
<attr name="visible" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="StateListDrawable">
|
||||
<attr name="visible" />
|
||||
<!-- If true, allows the drawable's padding to change based on the
|
||||
@@ -2139,7 +2139,7 @@
|
||||
current state. -->
|
||||
<attr name="constantSize" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="AnimationDrawable">
|
||||
<attr name="visible" />
|
||||
<attr name="variablePadding" />
|
||||
@@ -2148,15 +2148,15 @@
|
||||
restarting at the first frame after the last has finished. -->
|
||||
<attr name="oneshot" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="AnimationDrawableItem">
|
||||
<!-- Amount of time (in milliseconds) to display this frame. -->
|
||||
<attr name="duration" format="integer" />
|
||||
<attr name="duration" format="integer" />
|
||||
<!-- Reference to a drawable resource to use for the frame. If not
|
||||
given, the drawable must be defined by the first child tag. -->
|
||||
<attr name="drawable" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawable">
|
||||
<attr name="visible" />
|
||||
<attr name="shape">
|
||||
@@ -2179,18 +2179,18 @@
|
||||
<attr name="thickness" format="dimension" />
|
||||
<attr name="useLevel" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawableSize">
|
||||
<attr name="width" />
|
||||
<attr name="height" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawableGradient">
|
||||
<attr name="startColor" format="color" />
|
||||
<!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. -->
|
||||
<attr name="centerColor" format="color" />
|
||||
<attr name="endColor" format="color" />
|
||||
<attr name="useLevel" format="boolean" />
|
||||
<attr name="useLevel" format="boolean" />
|
||||
<attr name="angle" format="float" />
|
||||
<attr name="type">
|
||||
<enum name="linear" value="0" />
|
||||
@@ -2201,18 +2201,18 @@
|
||||
<attr name="centerY" format="float|fraction" />
|
||||
<attr name="gradientRadius" format="float|fraction" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawableSolid">
|
||||
<attr name="color" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawableStroke">
|
||||
<attr name="width" />
|
||||
<attr name="color" />
|
||||
<attr name="dashWidth" format="dimension" />
|
||||
<attr name="dashGap" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="DrawableCorners">
|
||||
<attr name="radius" format="dimension" />
|
||||
<attr name="topLeftRadius" format="dimension" />
|
||||
@@ -2220,14 +2220,14 @@
|
||||
<attr name="bottomLeftRadius" format="dimension" />
|
||||
<attr name="bottomRightRadius" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="GradientDrawablePadding">
|
||||
<attr name="left" format="dimension" />
|
||||
<attr name="top" format="dimension" />
|
||||
<attr name="right" format="dimension" />
|
||||
<attr name="bottom" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="LayerDrawableItem">
|
||||
<attr name="left" />
|
||||
<attr name="top" />
|
||||
@@ -2236,7 +2236,7 @@
|
||||
<attr name="drawable" />
|
||||
<attr name="id" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="LevelListDrawableItem">
|
||||
<!-- The minimum level allowed for this item. -->
|
||||
<attr name="minLevel" format="integer" />
|
||||
@@ -2244,7 +2244,7 @@
|
||||
<attr name="maxLevel" format="integer" />
|
||||
<attr name="drawable" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="RotateDrawable">
|
||||
<attr name="visible" />
|
||||
<attr name="fromDegrees" format="float" />
|
||||
@@ -2400,7 +2400,7 @@
|
||||
<declare-styleable name="AnimationSet">
|
||||
<attr name="shareInterpolator" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="Animation">
|
||||
<!-- Defines the interpolator used to smooth the animation movement in time. -->
|
||||
<attr name="interpolator" />
|
||||
@@ -2443,14 +2443,14 @@
|
||||
<enum name="bottom" value="-1" />
|
||||
</attr>
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="RotateAnimation">
|
||||
<attr name="fromDegrees" />
|
||||
<attr name="toDegrees" />
|
||||
<attr name="pivotX" />
|
||||
<attr name="pivotY" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="ScaleAnimation">
|
||||
<attr name="fromXScale" format="float" />
|
||||
<attr name="toXScale" format="float" />
|
||||
@@ -2459,14 +2459,14 @@
|
||||
<attr name="pivotX" />
|
||||
<attr name="pivotY" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="TranslateAnimation">
|
||||
<attr name="fromXDelta" format="float|fraction" />
|
||||
<attr name="toXDelta" format="float|fraction" />
|
||||
<attr name="fromYDelta" format="float|fraction" />
|
||||
<attr name="toYDelta" format="float|fraction" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="AlphaAnimation">
|
||||
<attr name="fromAlpha" format="float" />
|
||||
<attr name="toAlpha" format="float" />
|
||||
@@ -2528,12 +2528,12 @@
|
||||
<!-- This is the amount of deceleration to ad when easing in. -->
|
||||
<attr name="factor" format="float" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="DecelerateInterpolator">
|
||||
<!-- This is the amount of acceleration to ad when easing out. -->
|
||||
<attr name="factor" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="CycleInterpolator">
|
||||
<attr name="cycles" format="float" />
|
||||
</declare-styleable>
|
||||
@@ -2626,18 +2626,18 @@
|
||||
</declare-styleable>
|
||||
<!-- State array representing an expandable list child's indicator. -->
|
||||
<declare-styleable name="ExpandableListChildIndicatorState">
|
||||
<!-- State identifier indicating the child is the last child within its group. -->
|
||||
<!-- State identifier indicating the child is the last child within its group. -->
|
||||
<attr name="state_last" />
|
||||
</declare-styleable>
|
||||
<!-- State array representing an expandable list group's indicator. -->
|
||||
<declare-styleable name="ExpandableListGroupIndicatorState">
|
||||
<!-- State identifier indicating the group is expanded. -->
|
||||
<!-- State identifier indicating the group is expanded. -->
|
||||
<attr name="state_expanded" format="boolean" />
|
||||
<!-- State identifier indicating the group is empty (has no children). -->
|
||||
<!-- State identifier indicating the group is empty (has no children). -->
|
||||
<attr name="state_empty" format="boolean" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="PopupWindowBackgroundState">
|
||||
<!-- State identifier indicating the popup will be above the anchor. -->
|
||||
<!-- State identifier indicating the popup will be above the anchor. -->
|
||||
<attr name="state_above_anchor" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
@@ -2647,7 +2647,7 @@
|
||||
<eat-comment />
|
||||
|
||||
<!-- Searchable activities and applications must provide search configuration information
|
||||
in an XML file, typically called searchable.xml. This file is referenced in your manifest.
|
||||
in an XML file, typically called searchable.xml. This file is referenced in your manifest.
|
||||
For a more in-depth discussion of search configuration, please refer to
|
||||
{@link android.app.SearchManager}. -->
|
||||
<declare-styleable name="Searchable">
|
||||
@@ -2656,29 +2656,29 @@
|
||||
plain text. This is a reference to a drawable (icon) resource.
|
||||
<i>Optional attribute.</i> -->
|
||||
<attr name="icon" />
|
||||
<!-- This is the user-displayed name of the searchable activity. <i>Required
|
||||
<!-- This is the user-displayed name of the searchable activity. <i>Required
|
||||
attribute.</i> -->
|
||||
<attr name="label" />
|
||||
<!-- If supplied, this string will be displayed as a hint to the user. <i>Optional
|
||||
<!-- If supplied, this string will be displayed as a hint to the user. <i>Optional
|
||||
attribute.</i> -->
|
||||
<attr name="hint" />
|
||||
<!-- If supplied, this string will be displayed as the text of the "Search" button.
|
||||
<i>Optional attribute.</i>
|
||||
<i>Optional attribute.</i>
|
||||
{@deprecated This will create a non-standard UI appearance, because the search bar UI is
|
||||
changing to use only icons for its buttons.}-->
|
||||
<attr name="searchButtonText" format="string" />
|
||||
<attr name="inputType" />
|
||||
<attr name="imeOptions" />
|
||||
|
||||
|
||||
<!-- Additional features are controlled by mode bits in this field. Omitting
|
||||
this field, or setting to zero, provides default behavior. <i>Optional attribute.</i>
|
||||
this field, or setting to zero, provides default behavior. <i>Optional attribute.</i>
|
||||
-->
|
||||
<attr name="searchMode">
|
||||
<!-- If set, this flag enables the display of the search target (label) within the
|
||||
search bar. If neither bad mode is selected, no badge will be shown. -->
|
||||
<flag name="showSearchLabelAsBadge" value="0x04" />
|
||||
<!-- If set, this flag enables the display of the search target (icon) within the
|
||||
search bar. (Note, overrides showSearchLabel) If neither bad mode is selected,
|
||||
search bar. (Note, overrides showSearchLabel) If neither bad mode is selected,
|
||||
no badge will be shown.-->
|
||||
<flag name="showSearchIconAsBadge" value="0x08" />
|
||||
<!-- If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA to
|
||||
@@ -2692,11 +2692,11 @@
|
||||
values are not suitable for user inspection and editing. -->
|
||||
<flag name="queryRewriteFromText" value="0x20" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- Voice search features are controlled by mode bits in this field. Omitting
|
||||
this field, or setting to zero, provides default behavior.
|
||||
If showVoiceSearchButton is set, then launchWebSearch or launchRecognizer must
|
||||
also be set. <i>Optional attribute.</i>
|
||||
also be set. <i>Optional attribute.</i>
|
||||
-->
|
||||
<attr name="voiceSearchMode">
|
||||
<!-- If set, display a voice search button. This only takes effect if voice search is
|
||||
@@ -2714,9 +2714,9 @@
|
||||
</attr>
|
||||
|
||||
<!-- If provided, this specifies the language model that should be used by the
|
||||
voice recognition system. See
|
||||
{@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
|
||||
If not provided, the default value
|
||||
voice recognition system. See
|
||||
{@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
|
||||
If not provided, the default value
|
||||
{@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM } will be used. -->
|
||||
<attr name="voiceLanguageModel" format="string" />
|
||||
<!-- If provided, this specifies a prompt that will be displayed during voice input. -->
|
||||
@@ -2726,14 +2726,14 @@
|
||||
<attr name="voiceLanguage" format="string" />
|
||||
<!-- If provided, enforces the maximum number of results to return, including the "best"
|
||||
result which will always be provided as the SEARCH intent's primary query. Must be one
|
||||
or greater. If not provided, the recognizer will choose how many results to return.
|
||||
or greater. If not provided, the recognizer will choose how many results to return.
|
||||
-->
|
||||
<attr name="voiceMaxResults" format="integer" />
|
||||
|
||||
<!-- If provided, this is the trigger indicating that the searchable activity
|
||||
provides suggestions as well. The value must be a fully-qualified content provider
|
||||
authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
|
||||
"android:authorities" tag in your content provider's manifest entry. <i>Optional
|
||||
authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
|
||||
"android:authorities" tag in your content provider's manifest entry. <i>Optional
|
||||
attribute.</i> -->
|
||||
<attr name="searchSuggestAuthority" format="string" />
|
||||
<!-- If provided, this will be inserted in the suggestions query Uri, after the authority
|
||||
@@ -2741,22 +2741,22 @@
|
||||
-->
|
||||
<attr name="searchSuggestPath" format="string" />
|
||||
<!-- If provided, suggestion queries will be passed into your query function
|
||||
as the <i>selection</i> parameter. Typically this will be a WHERE clause for your
|
||||
database, and will contain a single question mark, which represents the actual query
|
||||
as the <i>selection</i> parameter. Typically this will be a WHERE clause for your
|
||||
database, and will contain a single question mark, which represents the actual query
|
||||
string that has been typed by the user. If not provided, then the user query text
|
||||
will be appended to the query Uri (after an additional "/".) <i>Optional
|
||||
will be appended to the query Uri (after an additional "/".) <i>Optional
|
||||
attribute.</i> -->
|
||||
<attr name="searchSuggestSelection" format="string" />
|
||||
|
||||
<!-- If provided, and not overridden by an action in the selected suggestion, this
|
||||
<!-- If provided, and not overridden by an action in the selected suggestion, this
|
||||
string will be placed in the action field of the {@link android.content.Intent Intent}
|
||||
when the user clicks a suggestion. <i>Optional attribute.</i> -->
|
||||
<attr name="searchSuggestIntentAction" format="string" />
|
||||
<!-- If provided, and not overridden by an action in the selected suggestion, this
|
||||
string will be placed in the data field of the {@link android.content.Intent Intent}
|
||||
<!-- If provided, and not overridden by an action in the selected suggestion, this
|
||||
string will be placed in the data field of the {@link android.content.Intent Intent}
|
||||
when the user clicks a suggestion. <i>Optional attribute.</i> -->
|
||||
<attr name="searchSuggestIntentData" format="string" />
|
||||
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
<!-- In order to process special action keys during search, you must define them using
|
||||
@@ -2766,70 +2766,70 @@
|
||||
<declare-styleable name="SearchableActionKey">
|
||||
<!-- This attribute denotes the action key you wish to respond to. Note that not
|
||||
all action keys are actually supported using this mechanism, as many of them are
|
||||
used for typing, navigation, or system functions. This will be added to the
|
||||
used for typing, navigation, or system functions. This will be added to the
|
||||
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
|
||||
searchable activity. To examine the key code, use
|
||||
searchable activity. To examine the key code, use
|
||||
{@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}.
|
||||
<p>Note, in addition to the keycode, you must also provide one or more of the action
|
||||
<p>Note, in addition to the keycode, you must also provide one or more of the action
|
||||
specifier attributes. <i>Required attribute.</i> -->
|
||||
<attr name="keycode" />
|
||||
|
||||
|
||||
<!-- If you wish to handle an action key during normal search query entry, you
|
||||
must define an action string here. This will be added to the
|
||||
must define an action string here. This will be added to the
|
||||
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
|
||||
searchable activity. To examine the string, use
|
||||
searchable activity. To examine the string, use
|
||||
{@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
|
||||
<i>Optional attribute.</i> -->
|
||||
<attr name="queryActionMsg" format="string" />
|
||||
|
||||
|
||||
<!-- If you wish to handle an action key while a suggestion is being displayed <i>and
|
||||
selected</i>, there are two ways to handle this. If <i>all</i> of your suggestions
|
||||
can handle the action key, you can simply define the action message using this
|
||||
attribute. This will be added to the
|
||||
can handle the action key, you can simply define the action message using this
|
||||
attribute. This will be added to the
|
||||
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
|
||||
searchable activity. To examine the string, use
|
||||
searchable activity. To examine the string, use
|
||||
{@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
|
||||
<i>Optional attribute.</i> -->
|
||||
<attr name="suggestActionMsg" format="string" />
|
||||
|
||||
|
||||
<!-- If you wish to handle an action key while a suggestion is being displayed <i>and
|
||||
selected</i>, but you do not wish to enable this action key for every suggestion,
|
||||
selected</i>, but you do not wish to enable this action key for every suggestion,
|
||||
then you can use this attribute to control it on a suggestion-by-suggestion basis.
|
||||
First, you must define a column (and name it here) where your suggestions will include
|
||||
First, you must define a column (and name it here) where your suggestions will include
|
||||
the action string. Then, in your content provider, you must provide this column, and
|
||||
when desired, provide data in this column.
|
||||
The search manager will look at your suggestion cursor, using the string
|
||||
provided here in order to select a column, and will use that to select a string from
|
||||
the cursor. That string will be added to the
|
||||
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
|
||||
your searchable activity. To examine the string, use
|
||||
{@link android.content.Intent#getStringExtra
|
||||
The search manager will look at your suggestion cursor, using the string
|
||||
provided here in order to select a column, and will use that to select a string from
|
||||
the cursor. That string will be added to the
|
||||
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
|
||||
your searchable activity. To examine the string, use
|
||||
{@link android.content.Intent#getStringExtra
|
||||
getStringExtra(SearchManager.ACTION_MSG)}. <i>If the data does not exist for the
|
||||
selection suggestion, the action key will be ignored.</i><i>Optional attribute.</i> -->
|
||||
<attr name="suggestActionMsgColumn" format="string" />
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- ***************************************************************** -->
|
||||
<!-- Support for MapView. -->
|
||||
<!-- ***************************************************************** -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- The set of attributes for a MapView. -->
|
||||
<declare-styleable name="MapView">
|
||||
<!-- Value is a string that specifies the Maps API Key to use. -->
|
||||
<attr name="apiKey" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- **************************************************************** -->
|
||||
<!-- Menu XML inflation. -->
|
||||
<!-- **************************************************************** -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Base attributes that are available to all Menu objects. -->
|
||||
<declare-styleable name="Menu">
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- Base attributes that are available to all groups. -->
|
||||
<declare-styleable name="MenuGroup">
|
||||
|
||||
@@ -2848,11 +2848,11 @@
|
||||
<!-- Items are alternative actions. -->
|
||||
<enum name="alternative" value="0x00040000" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- The order within the category applied to all items within this group.
|
||||
(This will be or'ed with the category attribute.) -->
|
||||
<attr name="orderInCategory" format="integer" />
|
||||
|
||||
|
||||
<!-- Whether the items are capable of displaying a check mark. -->
|
||||
<attr name="checkableBehavior">
|
||||
<!-- The items are not checkable. -->
|
||||
@@ -2863,7 +2863,7 @@
|
||||
this group. -->
|
||||
<enum name="single" value="2" />
|
||||
</attr>
|
||||
|
||||
|
||||
<!-- Whether the items are shown/visible. -->
|
||||
<attr name="visible" />
|
||||
|
||||
@@ -2877,7 +2877,7 @@
|
||||
|
||||
<!-- The ID of the item. -->
|
||||
<attr name="id" />
|
||||
|
||||
|
||||
<!-- The category applied to the item.
|
||||
(This will be or'ed with the orderInCategory attribute.) -->
|
||||
<attr name="menuCategory" />
|
||||
@@ -2888,15 +2888,15 @@
|
||||
|
||||
<!-- The title associated with the item. -->
|
||||
<attr name="title" format="string" />
|
||||
|
||||
|
||||
<!-- The condensed title associated with the item. This is used in situations where the
|
||||
normal title may be too long to be displayed. -->
|
||||
<attr name="titleCondensed" format="string" />
|
||||
|
||||
<!-- The icon associated with this item. This icon will not always be shown, so
|
||||
the title should be sufficient in describing this item. -->
|
||||
the title should be sufficient in describing this item. -->
|
||||
<attr name="icon" />
|
||||
|
||||
|
||||
<!-- The alphabetic shortcut key. This is the shortcut when using a keyboard
|
||||
with alphabetic keys. -->
|
||||
<attr name="alphabeticShortcut" format="string" />
|
||||
@@ -2904,14 +2904,14 @@
|
||||
<!-- The numeric shortcut key. This is the shortcut when using a numeric (e.g., 12-key)
|
||||
keyboard. -->
|
||||
<attr name="numericShortcut" format="string" />
|
||||
|
||||
|
||||
<!-- Whether the item is capable of displaying a check mark. -->
|
||||
<attr name="checkable" format="boolean" />
|
||||
|
||||
<!-- Whether the item is checked. Note that you must first have enabled checking with
|
||||
|
||||
<!-- Whether the item is checked. Note that you must first have enabled checking with
|
||||
the checkable attribute or else the check mark will not appear. -->
|
||||
<attr name="checked" />
|
||||
|
||||
|
||||
<!-- Whether the item is shown/visible. -->
|
||||
<attr name="visible" />
|
||||
|
||||
@@ -2937,7 +2937,7 @@
|
||||
with a View's attributes. Some subclasses (e.g., EditTextPreference)
|
||||
proxy all attributes to its EditText widget. -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<!-- Base attributes available to Preference. -->
|
||||
<declare-styleable name="Preference">
|
||||
<!-- The key to store the Preference value. -->
|
||||
@@ -3066,7 +3066,7 @@
|
||||
it had previously been shown. -->
|
||||
<attr name="imeExtractExitAnimation" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="KeyboardView">
|
||||
<!-- Default KeyboardView style. -->
|
||||
<attr name="keyboardViewStyle" format="reference" />
|
||||
@@ -3099,13 +3099,13 @@
|
||||
|
||||
<!-- Layout resource for popup keyboards -->
|
||||
<attr name="popupLayout" format="reference" />
|
||||
|
||||
|
||||
<attr name="shadowColor" />
|
||||
<attr name="shadowRadius" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<declare-styleable name="KeyboardViewPreviewState">
|
||||
<!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
|
||||
<!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
|
||||
key preview background -->
|
||||
<attr name="state_long_pressable" format="boolean" />
|
||||
</declare-styleable>
|
||||
@@ -3188,7 +3188,20 @@
|
||||
If not supplied, then no activity will be launched. -->
|
||||
<attr name="configure" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- Accounts package class attributes -->
|
||||
<!-- =============================== -->
|
||||
|
||||
<!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
|
||||
describes an account authenticator.
|
||||
-->
|
||||
<declare-styleable name="AccountAuthenticator">
|
||||
<!-- the account type this authenticator handles. -->
|
||||
<attr name="accountType" format="string"/>
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
***************************************************************
|
||||
IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
|
||||
READ THIS BEFORE YOU MAKE ANY CHANGES
|
||||
|
||||
|
||||
This file defines the binary compatibility for resources. As such,
|
||||
you must be very careful when making changes here, or you will
|
||||
completely break backwards compatibility with old applications.
|
||||
|
||||
|
||||
To avoid breaking compatibility, all new resources must be placed
|
||||
at the end of the list of resources of the same type. Placing a resource
|
||||
in the middle of type will cause all following resources to be
|
||||
assigned new resource numbers, breaking compatibility.
|
||||
|
||||
|
||||
***************************************************************
|
||||
*************************************************************** -->
|
||||
<resources>
|
||||
@@ -22,7 +22,7 @@
|
||||
<!-- We don't want to publish private symbols in android.R as part of the
|
||||
SDK. Instead, put them here. -->
|
||||
<private-symbols package="com.android.internal" />
|
||||
|
||||
|
||||
<!-- AndroidManifest.xml attributes. -->
|
||||
<eat-comment />
|
||||
|
||||
@@ -569,10 +569,10 @@
|
||||
<public type="attr" name="lineSpacingExtra" id="0x01010217" />
|
||||
<public type="attr" name="lineSpacingMultiplier" id="0x01010218" />
|
||||
<public type="attr" name="listChoiceIndicatorSingle" id="0x01010219" />
|
||||
<public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
|
||||
<public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
|
||||
<public type="attr" name="versionCode" id="0x0101021b" />
|
||||
<public type="attr" name="versionName" id="0x0101021c" />
|
||||
|
||||
|
||||
<public type="id" name="background" id="0x01020000" />
|
||||
<public type="id" name="checkbox" id="0x01020001" />
|
||||
<public type="id" name="content" id="0x01020002" />
|
||||
@@ -601,7 +601,7 @@
|
||||
<public type="id" name="button1" id="0x01020019" />
|
||||
<public type="id" name="button2" id="0x0102001a" />
|
||||
<public type="id" name="button3" id="0x0102001b" />
|
||||
|
||||
|
||||
<public type="style" name="Animation" id="0x01030000" />
|
||||
<public type="style" name="Animation.Activity" id="0x01030001" />
|
||||
<public type="style" name="Animation.Dialog" id="0x01030002" />
|
||||
@@ -748,7 +748,7 @@
|
||||
<public type="drawable" name="btn_plus" id="0x01080008" />
|
||||
<public type="drawable" name="btn_radio" id="0x01080009" />
|
||||
<public type="drawable" name="btn_star" id="0x0108000a" />
|
||||
<public type="drawable" name="btn_star_big_off" id="0x0108000b" />
|
||||
<public type="drawable" name="btn_star_big_off" id="0x0108000b" />
|
||||
<public type="drawable" name="btn_star_big_on" id="0x0108000c" />
|
||||
<public type="drawable" name="button_onoff_indicator_on" id="0x0108000d" />
|
||||
<public type="drawable" name="button_onoff_indicator_off" id="0x0108000e" />
|
||||
@@ -916,7 +916,7 @@
|
||||
<public type="layout" name="select_dialog_item" id="0x01090011" />
|
||||
<public type="layout" name="select_dialog_singlechoice" id="0x01090012" />
|
||||
<public type="layout" name="select_dialog_multichoice" id="0x01090013" />
|
||||
|
||||
|
||||
<public type="anim" name="fade_in" id="0x010a0000" />
|
||||
<public type="anim" name="fade_out" id="0x010a0001" />
|
||||
<public type="anim" name="slide_in_left" id="0x010a0002" />
|
||||
@@ -929,9 +929,9 @@
|
||||
Resources added in version 2 of the platform.
|
||||
=============================================================== -->
|
||||
<eat-comment />
|
||||
|
||||
|
||||
<public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
|
||||
|
||||
|
||||
<!-- ===============================================================
|
||||
Resources added in version 3 of the platform.
|
||||
=============================================================== -->
|
||||
@@ -1063,7 +1063,7 @@
|
||||
<public type="id" name="stopSelectingText" id="0x01020029" />
|
||||
<!-- Menu ID to perform a "add to dictionary" operation. -->
|
||||
<public type="id" name="addToDictionary" id="0x0102002a" />
|
||||
|
||||
|
||||
<public type="style" name="Theme.InputMethod" id="0x01030054" />
|
||||
<public type="style" name="Theme.NoDisplay" id="0x01030055" />
|
||||
<public type="style" name="Animation.InputMethod" id="0x01030056" />
|
||||
@@ -1071,7 +1071,7 @@
|
||||
<public type="style" name="ButtonBar" id="0x01030058" />
|
||||
<public type="style" name="Theme.Panel" id="0x01030059" />
|
||||
<public type="style" name="Theme.Light.Panel" id="0x0103005a" />
|
||||
|
||||
|
||||
<public type="string" name="dialog_alert_title" id="0x01040014" />
|
||||
<public type="string" name="VideoView_error_text_invalid_progressive_playback" id="0x01040015" />
|
||||
|
||||
@@ -1092,7 +1092,7 @@
|
||||
<public type="drawable" name="emo_im_winking" id="0x010800b2" />
|
||||
<public type="drawable" name="emo_im_wtf" id="0x010800b3" />
|
||||
<public type="drawable" name="emo_im_yelling" id="0x010800b4" />
|
||||
|
||||
|
||||
<public type="drawable" name="ic_btn_speak_now" id="0x010800b5" />
|
||||
|
||||
<!-- Drawable to use as a background for separators on a list with a dark background -->
|
||||
@@ -1100,8 +1100,14 @@
|
||||
|
||||
<!-- Drawable to use as a background for a taller version of the titlebar -->
|
||||
<public type="drawable" name="title_bar_tall" id="0x010800b7" />
|
||||
|
||||
<public type="integer" name="config_shortAnimTime" id="0x010e0000" />
|
||||
<public type="integer" name="config_mediumAnimTime" id="0x010e0001" />
|
||||
<public type="integer" name="config_longAnimTime" id="0x010e0002" />
|
||||
|
||||
<!-- ===============================================================
|
||||
Resources added in version 4 of the platform.
|
||||
=============================================================== -->
|
||||
<eat-comment />
|
||||
|
||||
<public type="attr" name="accountType" id="0x01010270" />
|
||||
</resources>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
|
||||
android.R$styleable
|
||||
android.accounts.AccountMonitor
|
||||
android.accounts.AccountMonitor$AccountUpdater
|
||||
android.app.Activity
|
||||
android.app.ActivityGroup
|
||||
android.app.ActivityManager$MemoryInfo$1
|
||||
|
||||
@@ -32,12 +32,7 @@ import android.content.pm.IPackageManager;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.media.AudioService;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.*;
|
||||
import android.provider.Contacts.People;
|
||||
import android.provider.Settings;
|
||||
import android.server.BluetoothA2dpService;
|
||||
@@ -45,6 +40,7 @@ import android.server.BluetoothDeviceService;
|
||||
import android.server.search.SearchManagerService;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.accounts.AccountManagerService;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -117,6 +113,14 @@ class ServerThread extends Thread {
|
||||
|
||||
mContentResolver = context.getContentResolver();
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Starting Account Manager.");
|
||||
ServiceManager.addService(Context.ACCOUNT_SERVICE,
|
||||
new AccountManagerService(context));
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "Failure starting Account Manager", e);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Starting Content Manager.");
|
||||
ContentService.main(context,
|
||||
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
framework=/system/framework
|
||||
bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
|
||||
adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \
|
||||
adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk:data/app/AndroidTests.apk \
|
||||
com.android.internal.util.WithFramework junit.textui.TestRunner $*
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.unit_tests.accounts;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.RenamingDelegatingContext;
|
||||
import android.test.IsolatedContext;
|
||||
import android.test.mock.MockContext;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.content.*;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManagerService;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
public class AccountManagerServiceTest extends AndroidTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
final String filenamePrefix = "test.";
|
||||
MockContentResolver resolver = new MockContentResolver();
|
||||
RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
|
||||
new MockContext(), // The context that most methods are delegated to
|
||||
getContext(), // The context that file methods are delegated to
|
||||
filenamePrefix);
|
||||
Context context = new IsolatedContext(resolver, targetContextWrapper);
|
||||
setContext(context);
|
||||
}
|
||||
|
||||
public class AccountSorter implements Comparator<Account> {
|
||||
public int compare(Account object1, Account object2) {
|
||||
if (object1 == object2) return 0;
|
||||
if (object1 == null) return 1;
|
||||
if (object2 == null) return -1;
|
||||
int result = object1.mType.compareTo(object2.mType);
|
||||
if (result != 0) return result;
|
||||
return object1.mName.compareTo(object2.mName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCheckAddAccount() throws Exception {
|
||||
AccountManagerService ams = new AccountManagerService(getContext());
|
||||
Account a11 = new Account("account1", "type1");
|
||||
Account a21 = new Account("account2", "type1");
|
||||
Account a31 = new Account("account3", "type1");
|
||||
Account a12 = new Account("account1", "type2");
|
||||
Account a22 = new Account("account2", "type2");
|
||||
Account a32 = new Account("account3", "type2");
|
||||
assertTrue(ams.addAccount(a11, "p11", null));
|
||||
assertTrue(ams.addAccount(a12, "p12", null));
|
||||
assertTrue(ams.addAccount(a21, "p21", null));
|
||||
assertTrue(ams.addAccount(a22, "p22", null));
|
||||
assertTrue(ams.addAccount(a31, "p31", null));
|
||||
assertTrue(ams.addAccount(a32, "p32", null));
|
||||
|
||||
assertFalse("duplicate account insertion should fail", ams.addAccount(a32, "p", null));
|
||||
|
||||
Account[] accounts = ams.getAccounts();
|
||||
Arrays.sort(accounts, new AccountSorter());
|
||||
assertEquals(6, accounts.length);
|
||||
assertEquals(a11, accounts[0]);
|
||||
assertEquals(a21, accounts[1]);
|
||||
assertEquals(a31, accounts[2]);
|
||||
assertEquals(a12, accounts[3]);
|
||||
assertEquals(a22, accounts[4]);
|
||||
assertEquals(a32, accounts[5]);
|
||||
|
||||
accounts = ams.getAccountsByType("type1");
|
||||
Arrays.sort(accounts, new AccountSorter());
|
||||
assertEquals(3, accounts.length);
|
||||
assertEquals(a11, accounts[0]);
|
||||
assertEquals(a21, accounts[1]);
|
||||
assertEquals(a31, accounts[2]);
|
||||
|
||||
ams.removeAccount(a21);
|
||||
|
||||
accounts = ams.getAccountsByType("type1");
|
||||
Arrays.sort(accounts, new AccountSorter());
|
||||
assertEquals(2, accounts.length);
|
||||
assertEquals(a11, accounts[0]);
|
||||
assertEquals(a31, accounts[1]);
|
||||
}
|
||||
|
||||
public void testPasswords() throws Exception {
|
||||
AccountManagerService ams = new AccountManagerService(getContext());
|
||||
Account a11 = new Account("account1", "type1");
|
||||
Account a12 = new Account("account1", "type2");
|
||||
assertTrue(ams.addAccount(a11, "p11", null));
|
||||
assertTrue(ams.addAccount(a12, "p12", null));
|
||||
|
||||
assertEquals("p11", ams.getPassword(a11));
|
||||
assertEquals("p12", ams.getPassword(a12));
|
||||
|
||||
ams.setPassword(a11, "p11b");
|
||||
|
||||
assertEquals("p11b", ams.getPassword(a11));
|
||||
assertEquals("p12", ams.getPassword(a12));
|
||||
}
|
||||
|
||||
public void testUserdata() throws Exception {
|
||||
AccountManagerService ams = new AccountManagerService(getContext());
|
||||
Account a11 = new Account("account1", "type1");
|
||||
Bundle u11 = new Bundle();
|
||||
u11.putString("a", "a_a11");
|
||||
u11.putString("b", "b_a11");
|
||||
u11.putString("c", "c_a11");
|
||||
Account a12 = new Account("account1", "type2");
|
||||
Bundle u12 = new Bundle();
|
||||
u12.putString("a", "a_a12");
|
||||
u12.putString("b", "b_a12");
|
||||
u12.putString("c", "c_a12");
|
||||
assertTrue(ams.addAccount(a11, "p11", u11));
|
||||
assertTrue(ams.addAccount(a12, "p12", u12));
|
||||
|
||||
assertEquals("a_a11", ams.getUserData(a11, "a"));
|
||||
assertEquals("b_a11", ams.getUserData(a11, "b"));
|
||||
assertEquals("c_a11", ams.getUserData(a11, "c"));
|
||||
assertEquals("a_a12", ams.getUserData(a12, "a"));
|
||||
assertEquals("b_a12", ams.getUserData(a12, "b"));
|
||||
assertEquals("c_a12", ams.getUserData(a12, "c"));
|
||||
|
||||
ams.setUserData(a11, "b", "b_a11b");
|
||||
|
||||
assertEquals("a_a11", ams.getUserData(a11, "a"));
|
||||
assertEquals("b_a11b", ams.getUserData(a11, "b"));
|
||||
assertEquals("c_a11", ams.getUserData(a11, "c"));
|
||||
assertEquals("a_a12", ams.getUserData(a12, "a"));
|
||||
assertEquals("b_a12", ams.getUserData(a12, "b"));
|
||||
assertEquals("c_a12", ams.getUserData(a12, "c"));
|
||||
}
|
||||
|
||||
public void testAuthtokens() throws Exception {
|
||||
AccountManagerService ams = new AccountManagerService(getContext());
|
||||
Account a11 = new Account("account1", "type1");
|
||||
Account a12 = new Account("account1", "type2");
|
||||
assertTrue(ams.addAccount(a11, "p11", null));
|
||||
assertTrue(ams.addAccount(a12, "p12", null));
|
||||
|
||||
ams.setAuthToken(a11, "att1", "a11_att1");
|
||||
ams.setAuthToken(a11, "att2", "a11_att2");
|
||||
ams.setAuthToken(a11, "att3", "a11_att3");
|
||||
ams.setAuthToken(a12, "att1", "a12_att1");
|
||||
ams.setAuthToken(a12, "att2", "a12_att2");
|
||||
ams.setAuthToken(a12, "att3", "a12_att3");
|
||||
|
||||
assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
|
||||
assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
|
||||
assertEquals("a11_att3", ams.peekAuthToken(a11, "att3"));
|
||||
assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
|
||||
assertEquals("a12_att2", ams.peekAuthToken(a12, "att2"));
|
||||
assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
|
||||
|
||||
ams.setAuthToken(a11, "att3", "a11_att3b");
|
||||
ams.invalidateAuthToken(a12.mType, "a12_att2");
|
||||
|
||||
assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
|
||||
assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
|
||||
assertEquals("a11_att3b", ams.peekAuthToken(a11, "att3"));
|
||||
assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
|
||||
assertNull(ams.peekAuthToken(a12, "att2"));
|
||||
assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
|
||||
|
||||
// check that the authtoken cache is consistent with the database
|
||||
assertEquals(5, ams.mAuthTokenCache.size());
|
||||
for (Map.Entry<AccountManagerService.AuthTokenKey, String> entry
|
||||
: ams.mAuthTokenCache.entrySet()) {
|
||||
assertEquals(entry.getValue(), ams.readAuthTokenFromDatabase(
|
||||
entry.getKey().mAccount, entry.getKey().mAuthTokenType));
|
||||
}
|
||||
assertNull(ams.readAuthTokenFromDatabase(a12, "att2"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user