diff options
72 files changed, 2162 insertions, 1555 deletions
diff --git a/api/current.xml b/api/current.xml index d57198473ab1..ee8d2eb86511 100644 --- a/api/current.xml +++ b/api/current.xml @@ -13463,6 +13463,23 @@ <parameter name="accountType" type="java.lang.String"> </parameter> </method> +<method name="getAccountRemovalAllowed" + return="android.os.Bundle" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="response" type="android.accounts.AccountAuthenticatorResponse"> +</parameter> +<parameter name="account" type="android.accounts.Account"> +</parameter> +<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException"> +</exception> +</method> <method name="getAuthToken" return="android.os.Bundle" abstract="true" @@ -13615,7 +13632,7 @@ visibility="public" > </field> -<field name="mName" +<field name="name" type="java.lang.String" transient="false" volatile="false" @@ -13625,7 +13642,7 @@ visibility="public" > </field> -<field name="mType" +<field name="type" type="java.lang.String" transient="false" volatile="false" @@ -13781,7 +13798,7 @@ visibility="public" > <method name="addAccount" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -13800,13 +13817,13 @@ </parameter> <parameter name="activity" type="android.app.Activity"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="addAccountExplicitly" - return="android.accounts.Future1<java.lang.Boolean>" + return="boolean" abstract="false" native="false" synchronized="false" @@ -13815,16 +13832,12 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Boolean>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="password" type="java.lang.String"> </parameter> <parameter name="extras" type="android.os.Bundle"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="addOnAccountsUpdatedListener" return="void" @@ -13843,81 +13856,6 @@ <parameter name="updateImmediately" type="boolean"> </parameter> </method> -<method name="blockingAddAccountExplicitly" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="password" type="java.lang.String"> -</parameter> -<parameter name="extras" type="android.os.Bundle"> -</parameter> -</method> -<method name="blockingClearPassword" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -</method> -<method name="blockingGetAccounts" - return="android.accounts.Account[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="blockingGetAccountsByType" - return="android.accounts.Account[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="accountType" type="java.lang.String"> -</parameter> -</method> -<method name="blockingGetAccountsWithTypeAndFeatures" - return="android.accounts.Account[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="type" type="java.lang.String"> -</parameter> -<parameter name="features" type="java.lang.String[]"> -</parameter> -<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException"> -</exception> -<exception name="IOException" type="java.io.IOException"> -</exception> -<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> -</exception> -</method> <method name="blockingGetAuthToken" return="java.lang.String" abstract="false" @@ -13941,139 +13879,8 @@ <exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> </exception> </method> -<method name="blockingGetAuthenticatorTypes" - return="android.accounts.AuthenticatorDescription[]" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="blockingGetPassword" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -</method> -<method name="blockingGetUserData" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="key" type="java.lang.String"> -</parameter> -</method> -<method name="blockingInvalidateAuthToken" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="accountType" type="java.lang.String"> -</parameter> -<parameter name="authToken" type="java.lang.String"> -</parameter> -</method> -<method name="blockingPeekAuthToken" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="authTokenType" type="java.lang.String"> -</parameter> -</method> -<method name="blockingRemoveAccount" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -</method> -<method name="blockingSetAuthToken" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="authTokenType" type="java.lang.String"> -</parameter> -<parameter name="authToken" type="java.lang.String"> -</parameter> -</method> -<method name="blockingSetPassword" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="password" type="java.lang.String"> -</parameter> -</method> -<method name="blockingSetUserData" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="account" type="android.accounts.Account"> -</parameter> -<parameter name="key" type="java.lang.String"> -</parameter> -<parameter name="value" type="java.lang.String"> -</parameter> -</method> <method name="clearPassword" - return="android.accounts.Future1<java.lang.Void>" + return="void" abstract="false" native="false" synchronized="false" @@ -14082,15 +13889,11 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="confirmCredentials" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -14103,13 +13906,13 @@ </parameter> <parameter name="activity" type="android.app.Activity"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="confirmPassword" - return="android.accounts.Future1<java.lang.Boolean>" + return="android.accounts.AccountManagerFuture<java.lang.Boolean>" abstract="false" native="false" synchronized="false" @@ -14122,13 +13925,13 @@ </parameter> <parameter name="password" type="java.lang.String"> </parameter> -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Boolean>"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<java.lang.Boolean>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="editProperties" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -14141,7 +13944,7 @@ </parameter> <parameter name="activity" type="android.app.Activity"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> @@ -14160,7 +13963,7 @@ </parameter> </method> <method name="getAccounts" - return="android.accounts.Future1<android.accounts.Account[]>" + return="android.accounts.Account[]" abstract="false" native="false" synchronized="false" @@ -14169,13 +13972,9 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.Account[]>"> -</parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="getAccountsByType" - return="android.accounts.Future1<android.accounts.Account[]>" + return="android.accounts.Account[]" abstract="false" native="false" synchronized="false" @@ -14184,15 +13983,11 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.Account[]>"> -</parameter> <parameter name="type" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> -<method name="getAccountsWithTypeAndFeatures" - return="android.accounts.Future2" +<method name="getAccountsByTypeAndFeatures" + return="android.accounts.AccountManagerFuture<android.accounts.Account[]>" abstract="false" native="false" synchronized="false" @@ -14205,13 +14000,13 @@ </parameter> <parameter name="features" type="java.lang.String[]"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.accounts.Account[]>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="getAuthToken" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -14228,13 +14023,13 @@ </parameter> <parameter name="activity" type="android.app.Activity"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="getAuthToken" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -14249,7 +14044,7 @@ </parameter> <parameter name="notifyAuthFailure" type="boolean"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> @@ -14276,13 +14071,13 @@ </parameter> <parameter name="loginOptions" type="android.os.Bundle"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> <method name="getAuthenticatorTypes" - return="android.accounts.Future1<android.accounts.AuthenticatorDescription[]>" + return="android.accounts.AuthenticatorDescription[]" abstract="false" native="false" synchronized="false" @@ -14291,13 +14086,9 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<android.accounts.AuthenticatorDescription[]>"> -</parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="getPassword" - return="android.accounts.Future1<java.lang.String>" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -14306,15 +14097,11 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="getUserData" - return="android.accounts.Future1<java.lang.String>" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -14323,17 +14110,13 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="key" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="invalidateAuthToken" - return="android.accounts.Future1<java.lang.Void>" + return="void" abstract="false" native="false" synchronized="false" @@ -14342,17 +14125,13 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="accountType" type="java.lang.String"> </parameter> <parameter name="authToken" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="peekAuthToken" - return="android.accounts.Future1<java.lang.String>" + return="java.lang.String" abstract="false" native="false" synchronized="false" @@ -14361,17 +14140,13 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.String>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="authTokenType" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="removeAccount" - return="android.accounts.Future1<java.lang.Void>" + return="android.accounts.AccountManagerFuture<java.lang.Boolean>" abstract="false" native="false" synchronized="false" @@ -14380,10 +14155,10 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> +<parameter name="callback" type="android.accounts.AccountManagerCallback<java.lang.Boolean>"> +</parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> @@ -14401,7 +14176,7 @@ </parameter> </method> <method name="setAuthToken" - return="android.accounts.Future1<java.lang.Void>" + return="void" abstract="false" native="false" synchronized="false" @@ -14410,19 +14185,15 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="authTokenType" type="java.lang.String"> </parameter> <parameter name="authToken" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="setPassword" - return="android.accounts.Future1<java.lang.Void>" + return="void" abstract="false" native="false" synchronized="false" @@ -14431,17 +14202,13 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="password" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="setUserData" - return="android.accounts.Future1<java.lang.Void>" + return="void" abstract="false" native="false" synchronized="false" @@ -14450,19 +14217,15 @@ deprecated="not deprecated" visibility="public" > -<parameter name="callback" type="android.accounts.Future1Callback<java.lang.Void>"> -</parameter> <parameter name="account" type="android.accounts.Account"> </parameter> <parameter name="key" type="java.lang.String"> </parameter> <parameter name="value" type="java.lang.String"> </parameter> -<parameter name="handler" type="android.os.Handler"> -</parameter> </method> <method name="updateCredentials" - return="android.accounts.Future2" + return="android.accounts.AccountManagerFuture<android.os.Bundle>" abstract="false" native="false" synchronized="false" @@ -14479,12 +14242,117 @@ </parameter> <parameter name="activity" type="android.app.Activity"> </parameter> -<parameter name="callback" type="android.accounts.Future2Callback"> +<parameter name="callback" type="android.accounts.AccountManagerCallback<android.os.Bundle>"> </parameter> <parameter name="handler" type="android.os.Handler"> </parameter> </method> </class> +<interface name="AccountManagerCallback" + abstract="true" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="run" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="future" type="android.accounts.AccountManagerFuture<V>"> +</parameter> +</method> +</interface> +<interface name="AccountManagerFuture" + abstract="true" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="java.util.concurrent.Future"> +</implements> +<method name="get" + return="V" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> +<exception name="ExecutionException" type="java.util.concurrent.ExecutionException"> +</exception> +<exception name="InterruptedException" type="java.lang.InterruptedException"> +</exception> +</method> +<method name="get" + return="V" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> +<parameter name="timeout" type="long"> +</parameter> +<parameter name="unit" type="java.util.concurrent.TimeUnit"> +</parameter> +<exception name="ExecutionException" type="java.util.concurrent.ExecutionException"> +</exception> +<exception name="InterruptedException" type="java.lang.InterruptedException"> +</exception> +<exception name="TimeoutException" type="java.util.concurrent.TimeoutException"> +</exception> +</method> +<method name="getResult" + return="V" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException"> +</exception> +<exception name="IOException" type="java.io.IOException"> +</exception> +<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> +</exception> +</method> +<method name="getResult" + return="V" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="timeout" type="long"> +</parameter> +<parameter name="unit" type="java.util.concurrent.TimeUnit"> +</parameter> +<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException"> +</exception> +<exception name="IOException" type="java.io.IOException"> +</exception> +<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> +</exception> +</method> +</interface> <class name="AuthenticatorDescription" extends="java.lang.Object" abstract="false" @@ -14952,148 +14820,29 @@ visibility="public" > </field> -<field name="USERDATA_KEY" +<field name="PASSWORD_KEY" type="java.lang.String" transient="false" volatile="false" - value=""userdata"" + value=""password"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -</class> -<interface name="Future1" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<implements name="java.util.concurrent.Future"> -</implements> -<method name="getResult" - return="V" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> -</exception> -</method> -<method name="getResult" - return="V" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="timeout" type="long"> -</parameter> -<parameter name="unit" type="java.util.concurrent.TimeUnit"> -</parameter> -<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> -</exception> -</method> -</interface> -<interface name="Future1Callback" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="run" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="future" type="android.accounts.Future1<V>"> -</parameter> -</method> -</interface> -<interface name="Future2" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<implements name="java.util.concurrent.Future"> -</implements> -<method name="getResult" - return="android.os.Bundle" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException"> -</exception> -<exception name="IOException" type="java.io.IOException"> -</exception> -<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> -</exception> -</method> -<method name="getResult" - return="android.os.Bundle" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="timeout" type="long"> -</parameter> -<parameter name="unit" type="java.util.concurrent.TimeUnit"> -</parameter> -<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException"> -</exception> -<exception name="IOException" type="java.io.IOException"> -</exception> -<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException"> -</exception> -</method> -</interface> -<interface name="Future2Callback" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="run" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" +<field name="USERDATA_KEY" + type="java.lang.String" + transient="false" + volatile="false" + value=""userdata"" + static="true" + final="true" deprecated="not deprecated" visibility="public" > -<parameter name="future" type="android.accounts.Future2"> -</parameter> -</method> -</interface> +</field> +</class> <interface name="IAccountAuthenticator" abstract="true" static="false" @@ -15179,6 +14928,23 @@ <exception name="RemoteException" type="android.os.RemoteException"> </exception> </method> +<method name="getAccountRemovalAllowed" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse"> +</parameter> +<parameter name="account" type="android.accounts.Account"> +</parameter> +<exception name="RemoteException" type="android.os.RemoteException"> +</exception> +</method> <method name="getAuthToken" return="void" abstract="true" diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index 3ce3ca36c9e7..38ae962ba114 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -188,6 +188,25 @@ public abstract class AbstractAccountAuthenticator { response.onResult(result); } } + + public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response, + Account account) throws RemoteException { + checkBinderPermission(); + try { + final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed( + new AccountAuthenticatorResponse(response), account); + if (result != null) { + response.onResult(result); + } + } catch (UnsupportedOperationException e) { + response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION, + "getAccountRemovalAllowed not supported"); + return; + } catch (NetworkErrorException e) { + response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage()); + return; + } + } } private void checkBinderPermission() { @@ -238,4 +257,10 @@ public abstract class AbstractAccountAuthenticator { Account account, String authTokenType, Bundle loginOptions); public abstract Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException; + public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, + Account account) throws NetworkErrorException { + final Bundle result = new Bundle(); + result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true); + return result; + } } diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 30c91b062534..7b83a3076db3 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -26,20 +26,20 @@ import android.text.TextUtils; * 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 final String name; + public final String type; 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); + return name.equals(other.name) && type.equals(other.type); } public int hashCode() { int result = 17; - result = 31 * result + mName.hashCode(); - result = 31 * result + mType.hashCode(); + result = 31 * result + name.hashCode(); + result = 31 * result + type.hashCode(); return result; } @@ -50,13 +50,13 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } - mName = name; - mType = type; + this.name = name; + this.type = type; } public Account(Parcel in) { - mName = in.readString(); - mType = in.readString(); + this.name = in.readString(); + this.type = in.readString(); } public int describeContents() { @@ -64,8 +64,8 @@ public class Account implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mName); - dest.writeString(mType); + dest.writeString(name); + dest.writeString(type); } public static final Creator<Account> CREATOR = new Creator<Account>() { @@ -79,6 +79,6 @@ public class Account implements Parcelable { }; public String toString() { - return "Account {name=" + mName + ", type=" + mType + "}"; + return "Account {name=" + name + ", type=" + type + "}"; } } diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 502abbb312f2..9f70534fb81a 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -26,8 +26,6 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.Parcelable; -import android.util.Config; -import android.util.Log; import java.io.IOException; import java.util.concurrent.Callable; @@ -80,258 +78,132 @@ public class AccountManager { return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); } - public String blockingGetPassword(Account account) { - ensureNotOnMainThread(); + public String getPassword(final Account account) { try { return mService.getPassword(account); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // will never happen throw new RuntimeException(e); } } - public Future1<String> getPassword(final Future1Callback<String> callback, - final Account account, final Handler handler) { - return startAsFuture(callback, handler, new Callable<String>() { - public String call() throws Exception { - return blockingGetPassword(account); - } - }); - } - - public String blockingGetUserData(Account account, String key) { - ensureNotOnMainThread(); + public String getUserData(final Account account, final String key) { try { return mService.getUserData(account, key); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // will never happen throw new RuntimeException(e); } } - public Future1<String> getUserData(Future1Callback<String> callback, - final Account account, final String key, Handler handler) { - return startAsFuture(callback, handler, new Callable<String>() { - public String call() throws Exception { - return blockingGetUserData(account, key); - } - }); - } - - public AuthenticatorDescription[] blockingGetAuthenticatorTypes() { - ensureNotOnMainThread(); + public AuthenticatorDescription[] getAuthenticatorTypes() { try { return mService.getAuthenticatorTypes(); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // will never happen throw new RuntimeException(e); } } - public Future1<AuthenticatorDescription[]> getAuthenticatorTypes( - Future1Callback<AuthenticatorDescription[]> callback, Handler handler) { - return startAsFuture(callback, handler, new Callable<AuthenticatorDescription[]>() { - public AuthenticatorDescription[] call() throws Exception { - return blockingGetAuthenticatorTypes(); - } - }); - } - - public Account[] blockingGetAccounts() { - ensureNotOnMainThread(); + public Account[] getAccounts() { try { - return mService.getAccounts(); + return mService.getAccounts(null); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen throw new RuntimeException(e); } } - public Account[] blockingGetAccountsByType(String accountType) { - ensureNotOnMainThread(); + public Account[] getAccountsByType(String type) { try { - return mService.getAccountsByType(accountType); + return mService.getAccounts(type); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen throw new RuntimeException(e); } } - public Future1<Account[]> getAccounts(Future1Callback<Account[]> callback, Handler handler) { - return startAsFuture(callback, handler, new Callable<Account[]>() { - public Account[] call() throws Exception { - return blockingGetAccounts(); - } - }); - } - - public Future1<Account[]> getAccountsByType(Future1Callback<Account[]> callback, - final String type, Handler handler) { - return startAsFuture(callback, handler, new Callable<Account[]>() { - public Account[] call() throws Exception { - return blockingGetAccountsByType(type); - } - }); - } - - public boolean blockingAddAccountExplicitly(Account account, String password, Bundle extras) { - ensureNotOnMainThread(); + public boolean addAccountExplicitly(Account account, String password, Bundle extras) { try { return mService.addAccount(account, password, extras); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen throw new RuntimeException(e); } } - public Future1<Boolean> addAccountExplicitly(final Future1Callback<Boolean> callback, - final Account account, final String password, final Bundle extras, - final Handler handler) { - return startAsFuture(callback, handler, new Callable<Boolean>() { - public Boolean call() throws Exception { - return blockingAddAccountExplicitly(account, password, extras); + public AccountManagerFuture<Boolean> removeAccount(final Account account, + AccountManagerCallback<Boolean> callback, Handler handler) { + return new Future2Task<Boolean>(handler, callback) { + public void doWork() throws RemoteException { + mService.removeAccount(mResponse, account); } - }); - } - - public void blockingRemoveAccount(Account account) { - ensureNotOnMainThread(); - try { - mService.removeAccount(account); - } catch (RemoteException e) { - // if this happens the entire runtime will restart - } - } - - public Future1<Void> removeAccount(Future1Callback<Void> callback, final Account account, - final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingRemoveAccount(account); - return null; + public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) { + throw new AuthenticatorException("no result in response"); + } + return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY); } - }); + }.start(); } - public void blockingInvalidateAuthToken(String accountType, String authToken) { - ensureNotOnMainThread(); + public void invalidateAuthToken(final String accountType, final String authToken) { try { mService.invalidateAuthToken(accountType, authToken); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen + throw new RuntimeException(e); } } - public Future1<Void> invalidateAuthToken(Future1Callback<Void> callback, - final String accountType, final String authToken, final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingInvalidateAuthToken(accountType, authToken); - return null; - } - }); - } - - public String blockingPeekAuthToken(Account account, String authTokenType) { - ensureNotOnMainThread(); + public String peekAuthToken(final Account account, final String authTokenType) { try { return mService.peekAuthToken(account, authTokenType); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen throw new RuntimeException(e); } } - public Future1<String> peekAuthToken(Future1Callback<String> callback, - final Account account, final String authTokenType, final Handler handler) { - return startAsFuture(callback, handler, new Callable<String>() { - public String call() throws Exception { - return blockingPeekAuthToken(account, authTokenType); - } - }); - } - - public void blockingSetPassword(Account account, String password) { - ensureNotOnMainThread(); + public void setPassword(final Account account, final String password) { try { mService.setPassword(account, password); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen + throw new RuntimeException(e); } } - public Future1<Void> setPassword(Future1Callback<Void> callback, - final Account account, final String password, final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingSetPassword(account, password); - return null; - } - }); - } - - public void blockingClearPassword(Account account) { - ensureNotOnMainThread(); + public void clearPassword(final Account account) { try { mService.clearPassword(account); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen + throw new RuntimeException(e); } } - public Future1<Void> clearPassword(final Future1Callback<Void> callback, final Account account, - final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingClearPassword(account); - return null; - } - }); - } - - public void blockingSetUserData(Account account, String key, String value) { - ensureNotOnMainThread(); + public void setUserData(final Account account, final String key, final String value) { try { mService.setUserData(account, key, value); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen + throw new RuntimeException(e); } } - public Future1<Void> setUserData(Future1Callback<Void> callback, - final Account account, final String key, final String value, final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingSetUserData(account, key, value); - return null; - } - }); - } - - public void blockingSetAuthToken(Account account, String authTokenType, String authToken) { - ensureNotOnMainThread(); + public void setAuthToken(Account account, final String authTokenType, final String authToken) { try { mService.setAuthToken(account, authTokenType, authToken); } catch (RemoteException e) { - // if this happens the entire runtime will restart + // won't ever happen + throw new RuntimeException(e); } } - public Future1<Void> setAuthToken(Future1Callback<Void> callback, - final Account account, final String authTokenType, final String authToken, - final Handler handler) { - return startAsFuture(callback, handler, new Callable<Void>() { - public Void call() throws Exception { - blockingSetAuthToken(account, authTokenType, authToken); - return null; - } - }); - } - public String blockingGetAuthToken(Account account, String authTokenType, boolean notifyAuthFailure) throws OperationCanceledException, IOException, AuthenticatorException { - ensureNotOnMainThread(); Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */, null /* handler */).getResult(); return bundle.getString(Constants.AUTHTOKEN_KEY); @@ -349,9 +221,9 @@ public class AccountManager { * @param loginOptions * @param activity the activity to launch the login intent, if necessary, and to which */ - public Future2 getAuthToken( + public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle loginOptions, - final Activity activity, Future2Callback callback, Handler handler) { + final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { if (activity == null) throw new IllegalArgumentException("activity is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); return new AmsTask(activity, handler, callback) { @@ -363,9 +235,9 @@ public class AccountManager { }.start(); } - public Future2 getAuthToken( + public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final boolean notifyAuthFailure, - Future2Callback callback, Handler handler) { + AccountManagerCallback<Bundle> callback, Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); return new AmsTask(null, handler, callback) { @@ -376,10 +248,10 @@ public class AccountManager { }.start(); } - public Future2 addAccount(final String accountType, + public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, - final Activity activity, Future2Callback callback, Handler handler) { + final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { mService.addAcount(mResponse, accountType, authTokenType, @@ -389,44 +261,45 @@ public class AccountManager { } /** @deprecated use {@link #confirmCredentials} instead */ - public Future1<Boolean> confirmPassword(final Account account, final String password, - Future1Callback<Boolean> callback, Handler handler) { - return new AMSTaskBoolean(handler, callback) { + public AccountManagerFuture<Boolean> confirmPassword(final Account account, final String password, + AccountManagerCallback<Boolean> callback, Handler handler) { + return new Future2Task<Boolean>(handler, callback) { public void doWork() throws RemoteException { - mService.confirmPassword(response, account, password); + mService.confirmPassword(mResponse, account, password); } - }; - } - - public Account[] blockingGetAccountsWithTypeAndFeatures(String type, String[] features) - throws AuthenticatorException, IOException, OperationCanceledException { - Future2 future = getAccountsWithTypeAndFeatures(type, features, - null /* callback */, null /* handler */); - Bundle result = future.getResult(); - Parcelable[] accountsTemp = result.getParcelableArray(Constants.ACCOUNTS_KEY); - if (accountsTemp == null) { - throw new AuthenticatorException("accounts should not be null"); - } - Account[] accounts = new Account[accountsTemp.length]; - for (int i = 0; i < accountsTemp.length; i++) { - accounts[i] = (Account) accountsTemp[i]; - } - return accounts; + public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) { + throw new AuthenticatorException("no result in response"); + } + return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY); + } + }.start(); } - public Future2 getAccountsWithTypeAndFeatures( + public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( final String type, final String[] features, - Future2Callback callback, Handler handler) { + AccountManagerCallback<Account[]> callback, Handler handler) { if (type == null) throw new IllegalArgumentException("type is null"); - return new AmsTask(null /* activity */, handler, callback) { + return new Future2Task<Account[]>(handler, callback) { public void doWork() throws RemoteException { - mService.getAccountsByTypeAndFeatures(mResponse, type, features); + mService.getAccountsByFeatures(mResponse, type, features); + } + public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(Constants.ACCOUNTS_KEY)) { + throw new AuthenticatorException("no result in response"); + } + final Parcelable[] parcelables = bundle.getParcelableArray(Constants.ACCOUNTS_KEY); + Account[] descs = new Account[parcelables.length]; + for (int i = 0; i < parcelables.length; i++) { + descs[i] = (Account) parcelables[i]; + } + return descs; } }.start(); } - public Future2 confirmCredentials(final Account account, final Activity activity, - final Future2Callback callback, + public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Activity activity, + final AccountManagerCallback<Bundle> callback, final Handler handler) { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { @@ -435,9 +308,9 @@ public class AccountManager { }.start(); } - public Future2 updateCredentials(final Account account, final String authTokenType, + public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType, final Bundle loginOptions, final Activity activity, - final Future2Callback callback, + final AccountManagerCallback<Bundle> callback, final Handler handler) { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { @@ -447,8 +320,8 @@ public class AccountManager { }.start(); } - public Future2 editProperties(final String accountType, final Activity activity, - final Future2Callback callback, + public AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity, + final AccountManagerCallback<Bundle> callback, final Handler handler) { return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { @@ -471,8 +344,8 @@ public class AccountManager { } } - private void postToHandler(Handler handler, final Future2Callback callback, - final Future2 future) { + private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback, + final AccountManagerFuture<Bundle> future) { handler = handler == null ? mMainHandler : handler; handler.post(new Runnable() { public void run() { @@ -483,87 +356,24 @@ public class AccountManager { private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener, final Account[] accounts) { - handler = handler == null ? mMainHandler : handler; - handler.post(new Runnable() { - public void run() { - listener.onAccountsUpdated(accounts); - } - }); - } - - private <V> void postToHandler(Handler handler, final Future1Callback<V> callback, - final Future1<V> future) { - handler = handler == null ? mMainHandler : handler; + final Account[] accountsCopy = new Account[accounts.length]; + // send a copy to make sure that one doesn't + // change what another sees + System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length); + handler = (handler == null) ? mMainHandler : handler; handler.post(new Runnable() { public void run() { - callback.run(future); + listener.onAccountsUpdated(accountsCopy); } }); } - private <V> Future1<V> startAsFuture(Future1Callback<V> callback, Handler handler, - Callable<V> callable) { - final FutureTaskWithCallback<V> task = - new FutureTaskWithCallback<V>(callback, callable, handler); - new Thread(task).start(); - return task; - } - - private class FutureTaskWithCallback<V> extends FutureTask<V> implements Future1<V> { - final Future1Callback<V> mCallback; - final Handler mHandler; - - public FutureTaskWithCallback(Future1Callback<V> callback, Callable<V> callable, - Handler handler) { - super(callable); - mCallback = callback; - mHandler = handler; - } - - protected void done() { - if (mCallback != null) { - postToHandler(mHandler, mCallback, this); - } - } - - public V internalGetResult(Long timeout, TimeUnit unit) throws OperationCanceledException { - try { - if (timeout == null) { - return get(); - } else { - return get(timeout, unit); - } - } catch (InterruptedException e) { - // we will cancel the task below - } catch (CancellationException e) { - // we will cancel the task below - } catch (TimeoutException e) { - // we will cancel the task below - } catch (ExecutionException e) { - // this should never happen - throw new IllegalStateException(e.getCause()); - } finally { - cancel(true /* interruptIfRunning */); - } - throw new OperationCanceledException(); - } - - public V getResult() throws OperationCanceledException { - return internalGetResult(null, null); - } - - public V getResult(long timeout, TimeUnit unit) throws OperationCanceledException { - return internalGetResult(null, null); - } - } - - private abstract class AmsTask extends FutureTask<Bundle> implements Future2 { + private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> { final IAccountManagerResponse mResponse; final Handler mHandler; - final Future2Callback mCallback; + final AccountManagerCallback<Bundle> mCallback; final Activity mActivity; - final Thread mThread; - public AmsTask(Activity activity, Handler handler, Future2Callback callback) { + public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) { super(new Callable<Bundle>() { public Bundle call() throws Exception { throw new IllegalStateException("this should never be called"); @@ -574,19 +384,14 @@ public class AccountManager { mCallback = callback; mActivity = activity; mResponse = new Response(); - mThread = new Thread(new Runnable() { - public void run() { - try { - doWork(); - } catch (RemoteException e) { - // never happens - } - } - }, "AmsTask"); } - public final Future2 start() { - mThread.start(); + public final AccountManagerFuture<Bundle> start() { + try { + doWork(); + } catch (RemoteException e) { + setException(e); + } return this; } @@ -594,6 +399,7 @@ public class AccountManager { private Bundle internalGetResult(Long timeout, TimeUnit unit) throws OperationCanceledException, IOException, AuthenticatorException { + ensureNotOnMainThread(); try { if (timeout == null) { return get(); @@ -676,42 +482,90 @@ public class AccountManager { } - private abstract class AMSTaskBoolean extends FutureTask<Boolean> implements Future1<Boolean> { - final IAccountManagerResponse response; + private abstract class BaseFutureTask<T> extends FutureTask<T> { + final public IAccountManagerResponse mResponse; final Handler mHandler; - final Future1Callback<Boolean> mCallback; - public AMSTaskBoolean(Handler handler, Future1Callback<Boolean> callback) { - super(new Callable<Boolean>() { - public Boolean call() throws Exception { + + public BaseFutureTask(Handler handler) { + super(new Callable<T>() { + public T call() throws Exception { throw new IllegalStateException("this should never be called"); } }); - mHandler = handler; - mCallback = callback; - response = new Response(); + mResponse = new Response(); + } - new Thread(new Runnable() { - public void run() { - try { - doWork(); - } catch (RemoteException e) { - // never happens + public abstract void doWork() throws RemoteException; + + public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException; + + protected void postRunnableToHandler(Runnable runnable) { + Handler handler = (mHandler == null) ? mMainHandler : mHandler; + handler.post(runnable); + } + + protected void startTask() { + try { + doWork(); + } catch (RemoteException e) { + setException(e); + } + } + + protected class Response extends IAccountManagerResponse.Stub { + public void onResult(Bundle bundle) { + try { + T result = bundleToResult(bundle); + if (result == null) { + return; } + set(result); + return; + } catch (ClassCastException e) { + // we will set the exception below + } catch (AuthenticatorException e) { + // we will set the exception below } - }).start(); - } + onError(Constants.ERROR_CODE_INVALID_RESPONSE, "no result in response"); + } - public abstract void doWork() throws RemoteException; + public void onError(int code, String message) { + if (code == Constants.ERROR_CODE_CANCELED) { + cancel(true /* mayInterruptIfRunning */); + return; + } + setException(convertErrorToException(code, message)); + } + } + } + private abstract class Future2Task<T> + extends BaseFutureTask<T> implements AccountManagerFuture<T> { + final AccountManagerCallback<T> mCallback; + public Future2Task(Handler handler, AccountManagerCallback<T> callback) { + super(handler); + mCallback = callback; + } protected void done() { if (mCallback != null) { - postToHandler(mHandler, mCallback, this); + postRunnableToHandler(new Runnable() { + public void run() { + mCallback.run(Future2Task.this); + } + }); } } - private Boolean internalGetResult(Long timeout, TimeUnit unit) { + public Future2Task<T> start() { + startTask(); + return this; + } + + private T internalGetResult(Long timeout, TimeUnit unit) + throws OperationCanceledException, IOException, AuthenticatorException { + ensureNotOnMainThread(); try { if (timeout == null) { return get(); @@ -723,15 +577,15 @@ public class AccountManager { } catch (TimeoutException e) { // fall through and cancel } catch (CancellationException e) { - return false; + // fall through and cancel } catch (ExecutionException e) { final Throwable cause = e.getCause(); if (cause instanceof IOException) { - return false; + throw (IOException) cause; } else if (cause instanceof UnsupportedOperationException) { - return false; + throw new AuthenticatorException(cause); } else if (cause instanceof AuthenticatorException) { - return false; + throw (AuthenticatorException) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { @@ -742,39 +596,19 @@ public class AccountManager { } finally { cancel(true /* interrupt if running */); } - return false; + throw new OperationCanceledException(); } - public Boolean getResult() throws OperationCanceledException { + public T getResult() + throws OperationCanceledException, IOException, AuthenticatorException { return internalGetResult(null, null); } - public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException { + public T getResult(long timeout, TimeUnit unit) + throws OperationCanceledException, IOException, AuthenticatorException { return internalGetResult(timeout, unit); } - private class Response extends IAccountManagerResponse.Stub { - public void onResult(Bundle bundle) { - try { - if (bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) { - set(bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY)); - return; - } - } catch (ClassCastException e) { - // we will set the exception below - } - onError(Constants.ERROR_CODE_INVALID_RESPONSE, "no result in response"); - } - - public void onError(int code, String message) { - if (code == Constants.ERROR_CODE_CANCELED) { - cancel(true /* mayInterruptIfRunning */); - return; - } - setException(convertErrorToException(code, message)); - } - } - } private Exception convertErrorToException(int code, String message) { @@ -797,11 +631,12 @@ public class AccountManager { return new AuthenticatorException(message); } - private class GetAuthTokenByTypeAndFeaturesTask extends AmsTask implements Future2Callback { + private class GetAuthTokenByTypeAndFeaturesTask + extends AmsTask implements AccountManagerCallback<Bundle> { GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType, final String[] features, Activity activityForPrompting, final Bundle addAccountOptions, final Bundle loginOptions, - Future2Callback callback, Handler handler) { + AccountManagerCallback<Bundle> callback, Handler handler) { super(activityForPrompting, handler, callback); if (accountType == null) throw new IllegalArgumentException("account type is null"); mAccountType = accountType; @@ -811,101 +646,100 @@ public class AccountManager { mLoginOptions = loginOptions; mMyCallback = this; } - volatile Future2 mFuture = null; + volatile AccountManagerFuture<Bundle> mFuture = null; final String mAccountType; final String mAuthTokenType; final String[] mFeatures; final Bundle mAddAccountOptions; final Bundle mLoginOptions; - final Future2Callback mMyCallback; + final AccountManagerCallback<Bundle> mMyCallback; public void doWork() throws RemoteException { - getAccountsWithTypeAndFeatures(mAccountType, mFeatures, new Future2Callback() { - public void run(Future2 future) { - Bundle getAccountsResult; - try { - getAccountsResult = future.getResult(); - } catch (OperationCanceledException e) { - setException(e); - return; - } catch (IOException e) { - setException(e); - return; - } catch (AuthenticatorException e) { - setException(e); - return; - } - - Parcelable[] accounts = - getAccountsResult.getParcelableArray(Constants.ACCOUNTS_KEY); - if (accounts.length == 0) { - if (mActivity != null) { - // no accounts, add one now. pretend that the user directly - // made this request - mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures, - mAddAccountOptions, mActivity, mMyCallback, mHandler); - } else { - // send result since we can't prompt to add an account - Bundle result = new Bundle(); - result.putString(Constants.ACCOUNT_NAME_KEY, null); - result.putString(Constants.ACCOUNT_TYPE_KEY, null); - result.putString(Constants.AUTHTOKEN_KEY, null); + getAccountsByTypeAndFeatures(mAccountType, mFeatures, + new AccountManagerCallback<Account[]>() { + public void run(AccountManagerFuture<Account[]> future) { + Account[] accounts; try { - mResponse.onResult(result); - } catch (RemoteException e) { - // this will never happen + accounts = future.getResult(); + } catch (OperationCanceledException e) { + setException(e); + return; + } catch (IOException e) { + setException(e); + return; + } catch (AuthenticatorException e) { + setException(e); + return; } - // we are done - } - } else if (accounts.length == 1) { - // have a single account, return an authtoken for it - if (mActivity == null) { - mFuture = getAuthToken((Account) accounts[0], mAuthTokenType, - false /* notifyAuthFailure */, mMyCallback, mHandler); - } else { - mFuture = getAuthToken((Account) accounts[0], - mAuthTokenType, mLoginOptions, - mActivity, mMyCallback, mHandler); - } - } else { - if (mActivity != null) { - IAccountManagerResponse chooseResponse = - new IAccountManagerResponse.Stub() { - public void onResult(Bundle value) throws RemoteException { - Account account = new Account( - value.getString(Constants.ACCOUNT_NAME_KEY), - value.getString(Constants.ACCOUNT_TYPE_KEY)); - mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions, + + if (accounts.length == 0) { + if (mActivity != null) { + // no accounts, add one now. pretend that the user directly + // made this request + mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures, + mAddAccountOptions, mActivity, mMyCallback, mHandler); + } else { + // send result since we can't prompt to add an account + Bundle result = new Bundle(); + result.putString(Constants.ACCOUNT_NAME_KEY, null); + result.putString(Constants.ACCOUNT_TYPE_KEY, null); + result.putString(Constants.AUTHTOKEN_KEY, null); + try { + mResponse.onResult(result); + } catch (RemoteException e) { + // this will never happen + } + // we are done + } + } else if (accounts.length == 1) { + // have a single account, return an authtoken for it + if (mActivity == null) { + mFuture = getAuthToken(accounts[0], mAuthTokenType, + false /* notifyAuthFailure */, mMyCallback, mHandler); + } else { + mFuture = getAuthToken(accounts[0], + mAuthTokenType, mLoginOptions, mActivity, mMyCallback, mHandler); } - - public void onError(int errorCode, String errorMessage) - throws RemoteException { - mResponse.onError(errorCode, errorMessage); + } else { + if (mActivity != null) { + IAccountManagerResponse chooseResponse = + new IAccountManagerResponse.Stub() { + public void onResult(Bundle value) throws RemoteException { + Account account = new Account( + value.getString(Constants.ACCOUNT_NAME_KEY), + value.getString(Constants.ACCOUNT_TYPE_KEY)); + mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions, + mActivity, mMyCallback, mHandler); + } + + public void onError(int errorCode, String errorMessage) + throws RemoteException { + mResponse.onError(errorCode, errorMessage); + } + }; + // have many accounts, launch the chooser + Intent intent = new Intent(); + intent.setClassName("android", + "android.accounts.ChooseAccountActivity"); + intent.putExtra(Constants.ACCOUNTS_KEY, accounts); + intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY, + new AccountManagerResponse(chooseResponse)); + mActivity.startActivity(intent); + // the result will arrive via the IAccountManagerResponse + } else { + // send result since we can't prompt to select an account + Bundle result = new Bundle(); + result.putString(Constants.ACCOUNTS_KEY, null); + try { + mResponse.onResult(result); + } catch (RemoteException e) { + // this will never happen + } + // we are done } - }; - // have many accounts, launch the chooser - Intent intent = new Intent(); - intent.setClassName("android", - "android.accounts.ChooseAccountActivity"); - intent.putExtra(Constants.ACCOUNTS_KEY, accounts); - intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY, - new AccountManagerResponse(chooseResponse)); - mActivity.startActivity(intent); - // the result will arrive via the IAccountManagerResponse - } else { - // send result since we can't prompt to select an account - Bundle result = new Bundle(); - result.putString(Constants.ACCOUNTS_KEY, null); - try { - mResponse.onResult(result); - } catch (RemoteException e) { - // this will never happen } - // we are done - } - } - }}, mHandler); + }}, mHandler); } @@ -915,7 +749,7 @@ public class AccountManager { // or to cause this to be canceled if mFuture isn't set. // Once this is done then getAuthTokenByFeatures can be changed to return a Future2. - public void run(Future2 future) { + public void run(AccountManagerFuture<Bundle> future) { try { set(future.get()); } catch (InterruptedException e) { @@ -932,7 +766,7 @@ public class AccountManager { final String accountType, final String authTokenType, final String[] features, final Activity activityForPrompting, final Bundle addAccountOptions, final Bundle loginOptions, - final Future2Callback callback, final Handler handler) { + final AccountManagerCallback<Bundle> callback, final Handler handler) { if (accountType == null) throw new IllegalArgumentException("account type is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features, @@ -942,13 +776,6 @@ public class AccountManager { private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners = Maps.newHashMap(); - // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver - // and its getAccounts() callback which are both invoked only on the main thread. As a - // result we don't need to protect against concurrent accesses and any changes are guaranteed - // to be visible when used. Basically, these two variables are thread-confined. - private Future1<Account[]> mAccountsLookupFuture = null; - private boolean mAccountLookupPending = false; - /** * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent * so that it can read the updated list of accounts and send them to the listener @@ -956,58 +783,14 @@ public class AccountManager { */ private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() { public void onReceive(final Context context, final Intent intent) { - if (mAccountsLookupFuture != null) { - // an accounts lookup is already in progress, - // don't bother starting another request - mAccountLookupPending = true; - return; - } - // initiate a read of the accounts - mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() { - public void run(Future1<Account[]> future) { - // clear the future so that future receives will try the lookup again - mAccountsLookupFuture = null; - - // get the accounts array - Account[] accounts; - try { - accounts = future.getResult(); - } catch (OperationCanceledException e) { - // this should never happen, but if it does pretend we got another - // accounts changed broadcast - if (Config.LOGD) { - Log.d(TAG, "the accounts lookup for listener notifications was " - + "canceled, try again by simulating the receipt of " - + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast"); - } - onReceive(context, intent); - return; - } - - // send the result to the listeners - synchronized (mAccountsUpdatedListeners) { - for (Map.Entry<OnAccountsUpdatedListener, Handler> entry : - mAccountsUpdatedListeners.entrySet()) { - Account[] accountsCopy = new Account[accounts.length]; - // send the listeners a copy to make sure that one doesn't - // change what another sees - System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length); - postToHandler(entry.getValue(), entry.getKey(), accountsCopy); - } - } - - // If mAccountLookupPending was set when the account lookup finished it - // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION - // intent because a lookup was already in progress. Now that we are done - // with this lookup and notification pretend that another intent - // was received by calling onReceive() directly. - if (mAccountLookupPending) { - mAccountLookupPending = false; - onReceive(context, intent); - return; - } + final Account[] accounts = getAccounts(); + // send the result to the listeners + synchronized (mAccountsUpdatedListeners) { + for (Map.Entry<OnAccountsUpdatedListener, Handler> entry : + mAccountsUpdatedListeners.entrySet()) { + postToHandler(entry.getValue(), entry.getKey(), accounts); } - }, mMainHandler); + } } }; @@ -1045,15 +828,7 @@ public class AccountManager { } if (updateImmediately) { - getAccounts(new Future1Callback<Account[]>() { - public void run(Future1<Account[]> future) { - try { - listener.onAccountsUpdated(future.getResult()); - } catch (OperationCanceledException e) { - // ignore - } - } - }, handler); + postToHandler(handler, listener, getAccounts()); } } diff --git a/core/java/android/accounts/Future1Callback.java b/core/java/android/accounts/AccountManagerCallback.java index 886671ba6b36..4aa7169088c5 100644 --- a/core/java/android/accounts/Future1Callback.java +++ b/core/java/android/accounts/AccountManagerCallback.java @@ -15,6 +15,6 @@ */ package android.accounts; -public interface Future1Callback<V> { - void run(Future1<V> future); -} +public interface AccountManagerCallback<V> { + void run(AccountManagerFuture<V> future); +}
\ No newline at end of file diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java new file mode 100644 index 000000000000..99393987462e --- /dev/null +++ b/core/java/android/accounts/AccountManagerFuture.java @@ -0,0 +1,65 @@ +/* + * 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 java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.io.IOException; + +/** + * An extension of {@link java.util.concurrent.Future} that provides wrappers for {@link #get()} + * that handle the various + * exceptions that {@link #get()} may return and rethrows them as exceptions specific to + * {@link android.accounts.AccountManager}. + */ +public interface AccountManagerFuture<V> extends Future<V> { + /** + * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws + * {@link InterruptedException} then the + * {@link AccountManagerFuture} is canceled and + * {@link android.accounts.OperationCanceledException} is thrown. + * @return the {@link android.os.Bundle} that is returned by get() + * @throws android.accounts.OperationCanceledException if get() throws the unchecked + * CancellationException + * or if the Future was interrupted. + */ + V getResult() throws OperationCanceledException, IOException, AuthenticatorException; + + /** + * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws + * {@link InterruptedException} then the + * {@link AccountManagerFuture} is canceled and + * {@link android.accounts.OperationCanceledException} is thrown. + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return the {@link android.os.Bundle} that is returned by + * {@link java.util.concurrent.Future#get()} + * @throws android.accounts.OperationCanceledException if get() throws the unchecked + * {@link java.util.concurrent.CancellationException} or if the {@link AccountManagerFuture} + * was interrupted. + */ + V getResult(long timeout, TimeUnit unit) + throws OperationCanceledException, IOException, AuthenticatorException; + + @Deprecated + V get() throws InterruptedException, ExecutionException; + + @Deprecated + V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException; +}
\ No newline at end of file diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 0c941bea3837..140c814394f6 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -214,50 +214,58 @@ public class AccountManagerService extends IAccountManager.Stub { long identityToken = clearCallingIdentity(); try { - 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(); - } + return readPasswordFromDatabase(account); } finally { restoreCallingIdentity(identityToken); } } + private String readPasswordFromDatabase(Account account) { + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD}, + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?", + new String[]{account.name, account.type}, null, null, null); + try { + if (cursor.moveToNext()) { + return cursor.getString(0); + } + return null; + } finally { + cursor.close(); + } + } + public String getUserData(Account account, String key) { checkAuthenticateAccountsPermission(account); long identityToken = clearCallingIdentity(); try { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - db.beginTransaction(); + return readUserDataFromDatabase(account, key); + } finally { + restoreCallingIdentity(identityToken); + } + } + + private String readUserDataFromDatabase(Account account, String key) { + 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 { - 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(); + if (cursor.moveToNext()) { + return cursor.getString(0); } + return null; } finally { - db.endTransaction(); + cursor.close(); } } finally { - restoreCallingIdentity(identityToken); + db.endTransaction(); } } @@ -280,39 +288,23 @@ public class AccountManagerService extends IAccountManager.Stub { } } - public Account[] getAccounts() { - checkReadAccountsPermission(); - long identityToken = clearCallingIdentity(); - try { - return getAccountsByType(null); - } finally { - restoreCallingIdentity(identityToken); - } - } - public Account[] getAccountsByType(String accountType) { - checkReadAccountsPermission(); - long identityToken = clearCallingIdentity(); - try { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + 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(); + 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 { - restoreCallingIdentity(identityToken); + cursor.close(); } } @@ -322,40 +314,44 @@ public class AccountManagerService extends IAccountManager.Stub { // fails if the account already exists long identityToken = clearCallingIdentity(); try { - 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; - } + return insertAccountIntoDatabase(account, password, extras); + } finally { + restoreCallingIdentity(identityToken); + } + } + + private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) { + 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.name, account.type}); + if (numMatches > 0) { + return false; + } + ContentValues values = new ContentValues(); + values.put(ACCOUNTS_NAME, account.name); + values.put(ACCOUNTS_TYPE, account.type); + 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(); - sendAccountsChangedBroadcast(); - return true; - } finally { - db.endTransaction(); } + db.setTransactionSuccessful(); + sendAccountsChangedBroadcast(); + return true; } finally { - restoreCallingIdentity(identityToken); + db.endTransaction(); } } @@ -367,19 +363,61 @@ public class AccountManagerService extends IAccountManager.Stub { return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values); } - public void removeAccount(Account account) { + public void removeAccount(IAccountManagerResponse response, Account account) { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); try { - final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?", - new String[]{account.mName, account.mType}); - sendAccountsChangedBroadcast(); + new RemoveAccountSession(response, account).bind(); } finally { restoreCallingIdentity(identityToken); } } + private class RemoveAccountSession extends Session { + final Account mAccount; + public RemoveAccountSession(IAccountManagerResponse response, Account account) { + super(response, account.type, false /* expectActivityLaunch */); + mAccount = account; + } + + protected String toDebugString(long now) { + return super.toDebugString(now) + ", removeAccount" + + ", account " + mAccount; + } + + public void run() throws RemoteException { + mAuthenticator.getAccountRemovalAllowed(this, mAccount); + } + + public void onResult(Bundle result) { + if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY) + && !result.containsKey(Constants.INTENT_KEY)) { + final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY); + if (removalAllowed) { + removeAccount(mAccount); + } + IAccountManagerResponse response = getResponseAndClose(); + if (response != null) { + Bundle result2 = new Bundle(); + result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed); + try { + response.onResult(result2); + } catch (RemoteException e) { + // ignore + } + } + } + super.onResult(result); + } + } + + private void removeAccount(Account account) { + final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?", + new String[]{account.name, account.type}); + sendAccountsChangedBroadcast(); + } + public void invalidateAuthToken(String accountType, String authToken) { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); @@ -398,6 +436,9 @@ public class AccountManagerService extends IAccountManager.Stub { } private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) { + if (authToken == null || accountType == null) { + return; + } Cursor cursor = db.rawQuery( "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME @@ -488,7 +529,7 @@ public class AccountManagerService extends IAccountManager.Stub { values.put(ACCOUNTS_PASSWORD, password); mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?", - new String[]{account.mName, account.mType}); + new String[]{account.name, account.type}); sendAccountsChangedBroadcast(); } finally { restoreCallingIdentity(identityToken); @@ -509,37 +550,55 @@ public class AccountManagerService extends IAccountManager.Stub { } } + private void sendResult(IAccountManagerResponse response, Bundle bundle) { + if (response != null) { + try { + response.onResult(bundle); + } catch (RemoteException e) { + // if the caller is dead then there is no one to care about remote + // exceptions + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "failure while notifying response", e); + } + } + } + } + public void setUserData(Account account, String key, String value) { checkAuthenticateAccountsPermission(account); long identityToken = clearCallingIdentity(); try { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - db.beginTransaction(); - try { - long accountId = getAccountId(db, account); - if (accountId < 0) { + writeUserdataIntoDatabase(account, key, value); + } finally { + restoreCallingIdentity(identityToken); + } + } + + private void writeUserdataIntoDatabase(Account account, String key, String value) { + 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; } - 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; - } - + } 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(); + } + db.setTransactionSuccessful(); } finally { - restoreCallingIdentity(identityToken); + db.endTransaction(); } } @@ -571,14 +630,14 @@ public class AccountManagerService extends IAccountManager.Stub { if (authToken != null) { Bundle result = new Bundle(); result.putString(Constants.AUTHTOKEN_KEY, authToken); - result.putString(Constants.ACCOUNT_NAME_KEY, account.mName); - result.putString(Constants.ACCOUNT_TYPE_KEY, account.mType); + result.putString(Constants.ACCOUNT_NAME_KEY, account.name); + result.putString(Constants.ACCOUNT_TYPE_KEY, account.type); onResult(response, result); return; } } - new Session(response, account.mType, expectActivityLaunch) { + new Session(response, account.type, expectActivityLaunch) { protected String toDebugString(long now) { if (loginOptions != null) loginOptions.keySet(); return super.toDebugString(now) + ", getAuthToken" @@ -651,7 +710,7 @@ public class AccountManagerService extends IAccountManager.Stub { mContext.getText(R.string.permission_request_notification_subtitle); n.setLatestEventInfo(mContext, mContext.getText(R.string.permission_request_notification_title), - String.format(subtitleFormatString.toString(), account.mName), + String.format(subtitleFormatString.toString(), account.name), PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)); ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)) .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n); @@ -661,9 +720,9 @@ public class AccountManagerService extends IAccountManager.Stub { AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) { RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo = mAuthenticatorCache.getServiceInfo( - AuthenticatorDescription.newKey(account.mType)); + AuthenticatorDescription.newKey(account.type)); if (serviceInfo == null) { - throw new IllegalArgumentException("unknown account type: " + account.mType); + throw new IllegalArgumentException("unknown account type: " + account.type); } final Context authContext; @@ -671,7 +730,7 @@ public class AccountManagerService extends IAccountManager.Stub { authContext = mContext.createPackageContext( serviceInfo.type.packageName, 0); } catch (PackageManager.NameNotFoundException e) { - throw new IllegalArgumentException("unknown account type: " + account.mType); + throw new IllegalArgumentException("unknown account type: " + account.type); } Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class); @@ -750,7 +809,7 @@ public class AccountManagerService extends IAccountManager.Stub { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); try { - new Session(response, account.mType, expectActivityLaunch) { + new Session(response, account.type, expectActivityLaunch) { public void run() throws RemoteException { mAuthenticator.confirmCredentials(this, account); } @@ -769,7 +828,7 @@ public class AccountManagerService extends IAccountManager.Stub { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); try { - new Session(response, account.mType, false /* expectActivityLaunch */) { + new Session(response, account.type, false /* expectActivityLaunch */) { public void run() throws RemoteException { mAuthenticator.confirmPassword(this, account, password); } @@ -789,7 +848,7 @@ public class AccountManagerService extends IAccountManager.Stub { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); try { - new Session(response, account.mType, expectActivityLaunch) { + new Session(response, account.type, expectActivityLaunch) { public void run() throws RemoteException { mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions); } @@ -898,10 +957,21 @@ public class AccountManagerService extends IAccountManager.Stub { + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null); } } - public void getAccountsByTypeAndFeatures(IAccountManagerResponse response, + + public Account[] getAccounts(String type) { + checkReadAccountsPermission(); + long identityToken = clearCallingIdentity(); + try { + return getAccountsByType(type); + } finally { + restoreCallingIdentity(identityToken); + } + } + + public void getAccountsByFeatures(IAccountManagerResponse response, String type, String[] features) { checkReadAccountsPermission(); - if (type == null) { + if (features != null && type == null) { if (response != null) { try { response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null"); @@ -913,6 +983,10 @@ public class AccountManagerService extends IAccountManager.Stub { } long identityToken = clearCallingIdentity(); try { + if (features == null || features.length == 0) { + getAccountsByType(type); + return; + } new GetAccountsByTypeAndFeatureSession(response, type, features).bind(); } finally { restoreCallingIdentity(identityToken); @@ -925,7 +999,7 @@ public class AccountManagerService extends IAccountManager.Stub { 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); + "name=? AND type=?", new String[]{account.name, account.type}, null, null, null); try { if (cursor.moveToNext()) { return cursor.getLong(0); @@ -1401,7 +1475,7 @@ public class AccountManagerService extends IAccountManager.Stub { } private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) { - final boolean fromAuthenticator = hasAuthenticatorUid(account.mType, callerUid); + final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid); final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid " @@ -1416,7 +1490,9 @@ public class AccountManagerService extends IAccountManager.Stub { for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo : mAuthenticatorCache.getAllServices()) { if (serviceInfo.type.type.equals(accountType)) { - return serviceInfo.uid == callingUid; + return (serviceInfo.uid == callingUid) || + (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid) + == PackageManager.SIGNATURE_MATCH); } } return false; @@ -1428,7 +1504,7 @@ public class AccountManagerService extends IAccountManager.Stub { } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType, - account.mName, account.mType}; + account.name, account.type}; final boolean permissionGranted = DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0; if (!permissionGranted && isDebuggableMonkeyBuild) { @@ -1444,7 +1520,7 @@ public class AccountManagerService extends IAccountManager.Stub { private void checkCallingUidAgainstAuthenticator(Account account) { final int uid = Binder.getCallingUid(); - if (!hasAuthenticatorUid(account.mType, uid)) { + if (!hasAuthenticatorUid(account.type, uid)) { String msg = "caller uid " + uid + " is different than the authenticator's uid"; Log.w(TAG, msg); throw new SecurityException(msg); diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java index 83377f352f0b..bd6f2054e668 100644 --- a/core/java/android/accounts/ChooseAccountActivity.java +++ b/core/java/android/accounts/ChooseAccountActivity.java @@ -45,7 +45,7 @@ public class ChooseAccountActivity extends ListActivity { String[] mAccountNames = new String[mAccounts.length]; for (int i = 0; i < mAccounts.length; i++) { - mAccountNames[i] = ((Account) mAccounts[i]).mName; + mAccountNames[i] = ((Account) mAccounts[i]).name; } // Use an existing ListAdapter that will map an array @@ -59,8 +59,8 @@ public class ChooseAccountActivity extends ListActivity { Account account = (Account) mAccounts[position]; Log.d(TAG, "selected account " + account); Bundle bundle = new Bundle(); - bundle.putString(Constants.ACCOUNT_NAME_KEY, account.mName); - bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.mType); + bundle.putString(Constants.ACCOUNT_NAME_KEY, account.name); + bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.type); mResult = bundle; finish(); } diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java index da8173f5f47b..8736f41216e8 100644 --- a/core/java/android/accounts/Constants.java +++ b/core/java/android/accounts/Constants.java @@ -31,6 +31,7 @@ public class Constants { public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types"; public static final String USERDATA_KEY = "userdata"; public static final String AUTHTOKEN_KEY = "authtoken"; + public static final String PASSWORD_KEY = "password"; public static final String ACCOUNT_NAME_KEY = "authAccount"; public static final String ACCOUNT_TYPE_KEY = "accountType"; public static final String ERROR_CODE_KEY = "errorCode"; diff --git a/core/java/android/accounts/Future1.java b/core/java/android/accounts/Future1.java deleted file mode 100644 index 386cb6ec2ad0..000000000000 --- a/core/java/android/accounts/Future1.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various - * exceptions that {@link #get()} may return and rethrows them as exceptions specific to - * {@link AccountManager}. - */ -public interface Future1<V> extends Future<V> { - /** - * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the - * {@link Future1} is canceled and {@link OperationCanceledException} is thrown. - * @return the {@link android.os.Bundle} that is returned by get() - * @throws OperationCanceledException if get() throws the unchecked CancellationException - * or if the Future was interrupted. - */ - V getResult() throws OperationCanceledException; - - /** - * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the - * {@link Future1} is canceled and {@link OperationCanceledException} is thrown. - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return the {@link android.os.Bundle} that is returned by {@link Future#get()} - * @throws OperationCanceledException if get() throws the unchecked - * {@link java.util.concurrent.CancellationException} or if the {@link Future1} was interrupted. - */ - V getResult(long timeout, TimeUnit unit) throws OperationCanceledException; -}
\ No newline at end of file diff --git a/core/java/android/accounts/Future2.java b/core/java/android/accounts/Future2.java deleted file mode 100644 index b2ea84f49306..000000000000 --- a/core/java/android/accounts/Future2.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.Bundle; - -import java.io.IOException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various - * exceptions that {@link #get()} may return and rethrows them as exceptions specific to - * {@link AccountManager}. - */ -public interface Future2 extends Future<Bundle> { - /** - * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the - * {@link Future2} is canceled and {@link OperationCanceledException} is thrown. - * @return the {@link android.os.Bundle} that is returned by {@link Future#get()} - * @throws OperationCanceledException if get() throws the unchecked - * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted. - * @throws IOException if the request was unable to complete due to a network error - * @throws AuthenticatorException if there was an error communicating with the - * {@link AbstractAccountAuthenticator}. - */ - Bundle getResult() - throws OperationCanceledException, IOException, AuthenticatorException; - - /** - * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the - * {@link Future2} is canceled and {@link OperationCanceledException} is thrown. - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return the {@link android.os.Bundle} that is returned by {@link Future#get()} - * @throws OperationCanceledException if get() throws the unchecked - * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted. - * @throws IOException if the request was unable to complete due to a network error - * @throws AuthenticatorException if there was an error communicating with the - * {@link AbstractAccountAuthenticator}. - */ - Bundle getResult(long timeout, TimeUnit unit) - throws OperationCanceledException, IOException, AuthenticatorException; -} diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java index f92d43f68e9b..e06afb4d5948 100644 --- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java +++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java @@ -63,12 +63,12 @@ public class GrantCredentialsPermissionActivity extends Activity implements View CharSequence grantCredentialsPermissionFormat = getResources().getText( R.string.grant_credentials_permission_message_desc); messageView.setText(String.format(grantCredentialsPermissionFormat.toString(), - mAccount.mName, accountTypeLabel)); + mAccount.name, accountTypeLabel)); } else { CharSequence grantCredentialsPermissionFormat = getResources().getText( R.string.grant_credentials_permission_message_with_authtokenlabel_desc); messageView.setText(String.format(grantCredentialsPermissionFormat.toString(), - authTokenLabel, mAccount.mName, accountTypeLabel)); + authTokenLabel, mAccount.name, accountTypeLabel)); } String[] packageLabels = new String[packages.length]; diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl index 7d4de392b6ef..48f053c2ef64 100644 --- a/core/java/android/accounts/IAccountAuthenticator.aidl +++ b/core/java/android/accounts/IAccountAuthenticator.aidl @@ -70,4 +70,9 @@ oneway interface IAccountAuthenticator { */ void hasFeatures(in IAccountAuthenticatorResponse response, in Account account, in String[] features); + + /** + * Gets whether or not the account is allowed to be removed. + */ + void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account); } diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 15ab4e822c50..411952b2664a 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -21,6 +21,7 @@ import android.accounts.Account; import android.accounts.AuthenticatorDescription; import android.os.Bundle; + /** * Central application service that provides account management. * @hide @@ -29,10 +30,10 @@ interface IAccountManager { String getPassword(in Account account); String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(); - Account[] getAccounts(); - Account[] getAccountsByType(String accountType); + Account[] getAccounts(String accountType); + void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features); boolean addAccount(in Account account, String password, in Bundle extras); - void removeAccount(in Account account); + void removeAccount(in IAccountManagerResponse response, 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); @@ -52,8 +53,6 @@ interface IAccountManager { boolean expectActivityLaunch); void confirmCredentials(in IAccountManagerResponse response, in Account account, boolean expectActivityLaunch); - void getAccountsByTypeAndFeatures(in IAccountManagerResponse response, String accountType, - in String[] features); /* * @deprecated diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java index 218f501ae92d..808f30ce9bb1 100644 --- a/core/java/android/content/AbstractSyncableContentProvider.java +++ b/core/java/android/content/AbstractSyncableContentProvider.java @@ -170,7 +170,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro // AbstractGDataSyncAdapter, which will put acore into a crash loop ArrayList<Account> gaiaAccounts = new ArrayList<Account>(); for (Account acct: accounts) { - if (acct.mType.equals("com.google.GAIA")) { + if (acct.type.equals("com.google.GAIA")) { gaiaAccounts.add(acct); } } @@ -693,7 +693,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro if (!accounts.containsKey(account)) { int numDeleted; numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?", - new String[]{account.mName, account.mType}); + new String[]{account.name, account.type}); if (Config.LOGV) { Log.v(TAG, "deleted " + numDeleted + " records from table " + table @@ -726,7 +726,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro // remove the data in the synced tables for (String table : tables) { db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE, - new String[]{account.mName, account.mType}); + new String[]{account.name, account.type}); } db.setTransactionSuccessful(); } finally { diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java index a3daa01e8317..9545fd7f1a74 100644 --- a/core/java/android/content/AbstractTableMerger.java +++ b/core/java/android/content/AbstractTableMerger.java @@ -174,7 +174,7 @@ public abstract class AbstractTableMerger Cursor diffsCursor = null; try { // load the local database entries, so we can merge them with the server - final String[] accountSelectionArgs = new String[]{account.mName, account.mType}; + final String[] accountSelectionArgs = new String[]{account.name, account.type}; localCursor = mDb.query(mTable, syncDirtyProjection, SELECT_MARKED, accountSelectionArgs, null, null, mTable + "." + _SYNC_ID); @@ -487,7 +487,7 @@ public abstract class AbstractTableMerger try { if (deleteBySyncId) { selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), - account.mName, account.mType}; + account.name, account.type}; c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs, null, null, null); } else { @@ -534,7 +534,7 @@ public abstract class AbstractTableMerger SyncableContentProvider clientDiffs = mergeResult.tempContentProvider; if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates"); - final String[] accountSelectionArgs = new String[]{account.mName, account.mType}; + final String[] accountSelectionArgs = new String[]{account.name, account.type}; // Generate the client updates and insertions // Create a cursor for dirty records diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index d54e26091d24..f25639496186 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -596,7 +596,7 @@ class SyncManager implements OnAccountsUpdatedListener { for (String authority : syncableAuthorities) { for (Account account : accounts) { - if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.mType)) + if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type)) != null) { scheduleSyncOperation( new SyncOperation(account, source, authority, extras, delay)); @@ -1094,8 +1094,8 @@ class SyncManager implements OnAccountsUpdatedListener { for (int i=0; i<N; i++) { SyncStorageEngine.PendingOperation op = ops.get(i); pw.print(" #"); pw.print(i); pw.print(": account="); - pw.print(op.account.mName); pw.print(":"); - pw.print(op.account.mType); pw.print(" authority="); + pw.print(op.account.name); pw.print(":"); + pw.print(op.account.type); pw.print(" authority="); pw.println(op.authority); if (op.extras != null && op.extras.size() > 0) { sb.setLength(0); @@ -1125,8 +1125,8 @@ class SyncManager implements OnAccountsUpdatedListener { processedAccounts.add(curAccount); - pw.print(" Account "); pw.print(authority.account.mName); - pw.print(" "); pw.print(authority.account.mType); + pw.print(" Account "); pw.print(authority.account.name); + pw.print(" "); pw.print(authority.account.type); pw.println(":"); for (int j=i; j<N; j++) { status = statuses.get(j); @@ -1248,9 +1248,9 @@ class SyncManager implements OnAccountsUpdatedListener { = mSyncStorageEngine.getAuthority(item.authorityId); pw.print(" #"); pw.print(i+1); pw.print(": "); if (authority != null) { - pw.print(authority.account.mName); + pw.print(authority.account.name); pw.print(":"); - pw.print(authority.account.mType); + pw.print(authority.account.type); pw.print(" "); pw.print(authority.authority); } else { @@ -1636,7 +1636,7 @@ class SyncManager implements OnAccountsUpdatedListener { // connect to the sync adapter SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority, - op.account.mType); + op.account.type); RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType); if (syncAdapterInfo == null) { diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java index dc728eccf3d4..64bbe25cefb0 100644 --- a/core/java/android/content/SyncStateContentProviderHelper.java +++ b/core/java/android/content/SyncStateContentProviderHelper.java @@ -172,7 +172,7 @@ public class SyncStateContentProviderHelper { */ public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest, Account account) { - final String[] whereArgs = new String[]{account.mName, account.mType}; + final String[] whereArgs = new String[]{account.name, account.type}; Cursor c = dbSrc.query(SYNC_STATE_TABLE, new String[]{"_sync_account", "_sync_account_type", "data"}, ACCOUNT_WHERE, whereArgs, null, null, null); @@ -209,7 +209,7 @@ public class SyncStateContentProviderHelper { public void discardSyncData(SQLiteDatabase db, Account account) { if (account != null) { - db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType}); + db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.name, account.type}); } else { db.delete(SYNC_STATE_TABLE, null, null); } @@ -220,7 +220,7 @@ public class SyncStateContentProviderHelper { */ public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) { Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE, - new String[]{account.mName, account.mType}, null, null, null); + new String[]{account.name, account.type}, null, null, null); try { if (c.moveToFirst()) { return c.getBlob(c.getColumnIndexOrThrow("data")); @@ -238,6 +238,6 @@ public class SyncStateContentProviderHelper { ContentValues values = new ContentValues(); values.put("data", data); db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE, - new String[]{account.mName, account.mType}); + new String[]{account.name, account.type}); } } diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 8cc06426c599..b3f9bbbb520f 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -1127,8 +1127,8 @@ public class SyncStorageEngine extends Handler { AuthorityInfo authority = mAuthorities.get(i); out.startTag(null, "authority"); out.attribute(null, "id", Integer.toString(authority.ident)); - out.attribute(null, "account", authority.account.mName); - out.attribute(null, "type", authority.account.mType); + out.attribute(null, "account", authority.account.name); + out.attribute(null, "type", authority.account.type); out.attribute(null, "authority", authority.authority); if (!authority.enabled) { out.attribute(null, "enabled", "false"); diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index 489d936dab86..fab3f3d034f7 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -174,7 +174,7 @@ public final class Calendar { return Calendar.Calendars.delete(cr, Calendar.Calendars._SYNC_ACCOUNT + "=? AND " + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?", - new String[] {account.mName, account.mType}); + new String[] {account.name, account.type}); } /** diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 7a1a9e4a91f4..11cb87f491fe 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1360,6 +1360,14 @@ public final class ContactsContract { * <P>Type: INTEGER</P> */ public static final String DELETED = "deleted"; + + /** + * Whether this group should be synced if the SYNC_EVERYTHING settings + * is false for this group's account. + * <p> + * Type: INTEGER (boolean) + */ + public static final String SHOULD_SYNC = "should_sync"; } /** diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java index b11abe844daf..b1cf6485f54c 100644 --- a/core/java/android/provider/Im.java +++ b/core/java/android/provider/Im.java @@ -1620,6 +1620,9 @@ public class Im { /** specifies the last heartbeat interval received from the server */ public static final String SETTING_HEARTBEAT_INTERVAL = "heartbeat_interval"; + /** specifiy the JID resource used for Google Talk connection */ + public static final String SETTING_JID_RESOURCE = "jid_resource"; + /** * Used for reliable message queue (RMQ). This is for storing the last rmq id received * from the GTalk server @@ -1861,6 +1864,14 @@ public class Im { putLongValue(contentResolver, providerId, SETTING_HEARTBEAT_INTERVAL, interval); } + /** + * A convenience method to set the jid resource. + */ + public static void setJidResource(ContentResolver contentResolver, + long providerId, String jidResource) { + putStringValue(contentResolver, providerId, SETTING_JID_RESOURCE, jidResource); + } + public static class QueryMap extends ContentQueryMap { private ContentResolver mContentResolver; private long mProviderId; @@ -2047,6 +2058,23 @@ public class Im { } /** + * Set the JID resource. + * + * @param jidResource the jid resource to be stored. + */ + public void setJidResource(String jidResource) { + ProviderSettings.setJidResource(mContentResolver, mProviderId, jidResource); + } + /** + * Get the JID resource used for the Google Talk connection + * + * @return the JID resource stored. + */ + public String getJidResource() { + return getString(SETTING_JID_RESOURCE, null); + } + + /** * Convenience function for retrieving a single settings value * as a boolean. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 85a2041aae05..d3e4c4c97ac5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -413,8 +413,6 @@ public final class Settings { private static final String TAG = "Settings"; - private static String sJidResource = null; - public static class SettingNotFoundException extends AndroidException { public SettingNotFoundException(String msg) { super(msg); @@ -3622,42 +3620,6 @@ public final class Settings { } /** - * Returns the GTalk JID resource associated with this device. - * - * @return String the JID resource of the device. It uses the device IMEI in the computation - * of the JID resource. If IMEI is not ready (i.e. telephony module not ready), we'll return - * an empty string. - * @hide - */ - // TODO: we shouldn't not have a permenant Jid resource, as that's an easy target for - // spams. We should change it once a while, like when we resubscribe to the subscription feeds - // server. - // (also, should this live in GTalkService?) - public static synchronized String getJidResource() { - if (sJidResource != null) { - return sJidResource; - } - - MessageDigest digest; - try { - digest = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("this should never happen"); - } - - String deviceId = TelephonyManager.getDefault().getDeviceId(); - if (TextUtils.isEmpty(deviceId)) { - return ""; - } - - byte[] hashedDeviceId = digest.digest(deviceId.getBytes()); - String id = new String(Base64.encodeBase64(hashedDeviceId), 0, 12); - id = id.replaceAll("/", "_"); - sJidResource = JID_RESOURCE_PREFIX + id; - return sJidResource; - } - - /** * Returns the device ID that we should use when connecting to the mobile gtalk server. * This is a string like "android-0x1242", where the hex string is the Android ID obtained * from the GoogleLoginService. diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java index f94b4427bd28..8e9f4021c934 100644 --- a/core/java/android/provider/SubscribedFeeds.java +++ b/core/java/android/provider/SubscribedFeeds.java @@ -119,8 +119,8 @@ public class SubscribedFeeds { String authority, String service) { ContentValues values = new ContentValues(); values.put(SubscribedFeeds.Feeds.FEED, feed); - values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName); - values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType); + values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.name); + values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.type); values.put(SubscribedFeeds.Feeds.AUTHORITY, authority); values.put(SubscribedFeeds.Feeds.SERVICE, service); return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values); @@ -134,7 +134,7 @@ public class SubscribedFeeds { where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?"); where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?"); return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI, - where.toString(), new String[] {account.mName, account.mType, feed, authority}); + where.toString(), new String[] {account.name, account.type, feed, authority}); } public static int deleteFeeds(ContentResolver resolver, @@ -144,7 +144,7 @@ public class SubscribedFeeds { where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?"); where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?"); return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI, - where.toString(), new String[] {account.mName, account.mType, authority}); + where.toString(), new String[] {account.name, account.type, authority}); } /** diff --git a/core/java/android/provider/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java index 7927e286ebca..5c93af046321 100644 --- a/core/java/android/provider/SyncStateContract.java +++ b/core/java/android/provider/SyncStateContract.java @@ -71,7 +71,7 @@ public class SyncStateContract { public static byte[] get(ContentProviderClient provider, Uri uri, Account account) throws RemoteException { Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT, - new String[]{account.mName, account.mType}, null); + new String[]{account.name, account.type}, null); try { if (c.moveToNext()) { return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA)); @@ -96,8 +96,8 @@ public class SyncStateContract { Account account, byte[] data) throws RemoteException { ContentValues values = new ContentValues(); values.put(Columns.DATA, data); - values.put(Columns.ACCOUNT_NAME, account.mName); - values.put(Columns.ACCOUNT_TYPE, account.mType); + values.put(Columns.ACCOUNT_NAME, account.name); + values.put(Columns.ACCOUNT_TYPE, account.type); provider.insert(uri, values); } @@ -116,8 +116,8 @@ public class SyncStateContract { values.put(Columns.DATA, data); return ContentProviderOperation .newInsert(uri) - .withValue(Columns.ACCOUNT_NAME, account.mName) - .withValue(Columns.ACCOUNT_TYPE, account.mType) + .withValue(Columns.ACCOUNT_NAME, account.name) + .withValue(Columns.ACCOUNT_TYPE, account.type) .withValues(values) .build(); } diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 96bf46ec9a29..e77d29b9ffb2 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -70,6 +70,9 @@ class CallbackProxy extends Handler { private final WebBackForwardList mBackForwardList; // Used to call startActivity during url override. private final Context mContext; + // Stores the URL being loaded and the viewing mode to switch into when + // the URL finishes loading. + private ChangeViewModeOnFinishedLoad mChange; // Message Ids private static final int PAGE_STARTED = 100; @@ -177,6 +180,37 @@ class CallbackProxy extends Handler { } /** + * Tell the host application that the WebView has changed viewing modes. + * @param toZoomedOut If true, the WebView has zoomed out so that the page + * fits the screen. If false, it is zoomed to the setting + * specified by the user. + */ + /* package */ void uiOnChangeViewingMode(boolean toZoomOverview) { + if (mWebChromeClient != null) { + mWebChromeClient.onChangeViewingMode(toZoomOverview); + } + } + + private static class ChangeViewModeOnFinishedLoad { + boolean mToZoomOverView; + String mOriginalUrl; + ChangeViewModeOnFinishedLoad(boolean toZoomOverview, + String originalUrl) { + mToZoomOverView = toZoomOverview; + mOriginalUrl = originalUrl; + } + } + + /** + * Keep track of the url and the viewing mode to change into. If/when that + * url finishes loading, this will change the viewing mode. + */ + /* package */ void uiChangeViewingModeOnFinishedLoad( + boolean toZoomOverview, String originalUrl) { + if (mWebChromeClient == null) return; + mChange = new ChangeViewModeOnFinishedLoad(toZoomOverview, originalUrl); + } + /** * Called by the UI side. Calling overrideUrlLoading from the WebCore * side will post a message to call this method. */ @@ -237,6 +271,15 @@ class CallbackProxy extends Handler { if (mWebViewClient != null) { mWebViewClient.onPageFinished(mWebView, (String) msg.obj); } + if (mChange != null) { + if (mWebView.getOriginalUrl().equals(mChange.mOriginalUrl)) { + uiOnChangeViewingMode(mChange.mToZoomOverView); + } else { + // The user has gone to a different page, so there is + // no need to hang on to the old object. + mChange = null; + } + } break; case RECEIVED_ICON: diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java index 81ed3670c708..c1eeb3b2a0b7 100644 --- a/core/java/android/webkit/FrameLoader.java +++ b/core/java/android/webkit/FrameLoader.java @@ -128,6 +128,18 @@ class FrameLoader { /* package */ static boolean handleLocalFile(String url, LoadListener loadListener, WebSettings settings) { + // Attempt to decode the percent-encoded url before passing to the + // local loaders. + try { + url = new String(URLUtil.decode(url.getBytes())); + } catch (IllegalArgumentException e) { + loadListener.error(EventHandler.ERROR_BAD_URL, + loadListener.getContext().getString( + com.android.internal.R.string.httpErrorBadUrl)); + // Return true here so we do not trigger an unsupported scheme + // error. + return true; + } if (URLUtil.isAssetUrl(url)) { FileLoader.requestUrl(url, loadListener, loadListener.getContext(), true, settings.getAllowFileAccess()); diff --git a/core/java/android/webkit/MockGeolocation.java b/core/java/android/webkit/MockGeolocation.java new file mode 100644 index 000000000000..028cb196a997 --- /dev/null +++ b/core/java/android/webkit/MockGeolocation.java @@ -0,0 +1,59 @@ +/* + * 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.webkit; + +/** + * This class is simply a container for the methods used to configure WebKit's + * mock Geolocation service for use in LayoutTests. + * @hide Pending API council review. + */ +public final class MockGeolocation { + + // Global instance of a MockGeolocation + private static MockGeolocation sMockGeolocation; + + /** + * Set the position for the mock Geolocation service. + */ + public void setPosition(double latitude, double longitude, double accuracy) { + // This should only ever be called on the WebKit thread. + nativeSetPosition(latitude, longitude, accuracy); + } + + /** + * Set the error for the mock Geolocation service. + */ + public void setError(int code, String message) { + // This should only ever be called on the WebKit thread. + nativeSetError(code, message); + } + + /** + * Get the global instance of MockGeolocation. + * @return The global MockGeolocation instance. + */ + public static MockGeolocation getInstance() { + if (sMockGeolocation == null) { + sMockGeolocation = new MockGeolocation(); + } + return sMockGeolocation; + } + + // Native functions + private static native void nativeSetPosition(double latitude, double longitude, double accuracy); + private static native void nativeSetError(int code, String message); +} diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index c10bc97de103..e1c8d4da409a 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -23,6 +23,15 @@ import android.view.View; public class WebChromeClient { /** + * Tell the host application that the WebView has changed viewing modes. + * @param toZoomedOut If true, the WebView has zoomed out so that the page + * fits the screen. If false, it is zoomed to the setting + * specified by the user. + * @hide + */ + public void onChangeViewingMode(boolean toZoomedOut) {} + + /** * Tell the host application the current progress of loading a page. * @param view The WebView that initiated the callback. * @param newProgress Current page loading progress, represented by diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index be9daa531ebe..7468aef5df75 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -521,6 +521,7 @@ public class WebView extends AbsoluteLayout // follow the links. Double tap will toggle between zoom overview mode and // the last zoom scale. boolean mInZoomOverview = false; + // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn, // engadget always have wider mContentWidth no matter what viewport size is. int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH; @@ -4687,6 +4688,7 @@ public class WebView extends AbsoluteLayout mZoomCenterX = mLastTouchX; mZoomCenterY = mLastTouchY; mInZoomOverview = !mInZoomOverview; + mCallbackProxy.uiOnChangeViewingMode(mInZoomOverview); if (mInZoomOverview) { if (getSettings().getBuiltInZoomControls()) { if (mZoomButtonsController.isVisible()) { @@ -5034,6 +5036,14 @@ public class WebView extends AbsoluteLayout mInZoomOverview = ENABLE_DOUBLETAP_ZOOM && settings.getLoadWithOverviewMode(); } + mCallbackProxy.uiOnChangeViewingMode(true); + if (!mInZoomOverview) { + // We are going to start zoomed in. However, we + // truly want to show the title bar, and then hide + // it once the page has loaded + mCallbackProxy.uiChangeViewingModeOnFinishedLoad( + false, getOriginalUrl()); + } setNewZoomScale(mLastScale, false); setContentScrollTo(restoreState.mScrollX, restoreState.mScrollY); diff --git a/core/res/res/values-en-rUS/donottranslate-names.xml b/core/res/res/values-en-rUS/donottranslate-names.xml new file mode 100644 index 000000000000..42c8ab48a703 --- /dev/null +++ b/core/res/res/values-en-rUS/donottranslate-names.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- various string resources for Contacts --> + <string-array name="common_nicknames"> + <item>Albert, Al, Bert, Bertie</item> + <item>Alexander, Al, Alex, Lex, Sasha</item> + <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item> + <item>Alice, Allie, Ally</item> + <item>Alison, Allie, Ally</item> + <item>Allison, Allie, Ally</item> + <item>Amanda, Mandi, Mandy</item> + <item>Andrea, Andie</item> + <item>Andrew, Andy, Drew</item> + <item>Anthony, Tony, Toni, Tone</item> + <item>Arthur, Art, Arty</item> + <item>Barbara, Babs, Barb, Barbie</item> + <item>Benjamin, Ben, Benji, Benny</item> + <item>Bernard, Bern, Bernie</item> + <item>Bertram, Bert, Bertie</item> + <item>Bradly, Brad</item> + <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item> + <item>Charles, Chuck, Chaz, Charlie, Buck</item> + <item>Christine, Chris, Chrissy, Chrissie</item> + <item>Christopher, Chris</item> + <item>Cynthia, Cindy, Cynth</item> + <item>Daniel, Dan, Danny</item> + <item>David, Dave</item> + <item>Deborah, Deb, Debbie</item> + <item>Dennis, Den, Denny, Dean</item> + <item>Dolores, Dolly</item> + <item>Donald, Don, Donny</item> + <item>Donnatella, Donna</item> + <item>Dorothea, Dot, Dotty</item> + <item>Dorothy, Dot, Dotty</item> + <item>Douglas, Doug</item> + <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item> + <item>Eleanor, Ella, Ellie, Elle</item> + <item>Elisabetta, Betta</item> + <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item> + <item>Emily, Em, Ems, Emmy</item> + <item>Emma, Em, Ems, Emmy</item> + <item>Erica, Rikki, Rikkie, Ricky</item> + <item>Eugene, Gene</item> + <item>Florence, Flo</item> + <item>Frances, Fran, Francie</item> + <item>Francis, Fran, Frank</item> + <item>Frederick, Fred, Freddy</item> + <item>Gabriel, Gabe</item> + <item>Geoffrey, Jeff</item> + <item>Gerald, Gerry</item> + <item>Gerard, Gerry</item> + <item>Gregory, Greg</item> + <item>Harold, Hal, Hank, Harry</item> + <item>Henry, Hal, Hank, Harry</item> + <item>Herbert, Bert, Bertie</item> + <item>Irving, Irv</item> + <item>Isabella, Isa, Izzy</item> + <item>Jacob, Jake</item> + <item>Jacqueline, Jackie</item> + <item>James, Jim, Jimmy, Jamie, Jock</item> + <item>Janet, Jan</item> + <item>Janice, Jan</item> + <item>Jason, Jay</item> + <item>Jefferson, Jeff</item> + <item>Jeffrey, Jeff</item> + <item>Jennifer, Jen, Jenny</item> + <item>Jerome, Jerry</item> + <item>Jessica, Jessie</item> + <item>John, Jack, Jacky, Johnny, Jon</item> + <item>Jonathan, Jon, John</item> + <item>Joseph, Joe, Joey</item> + <item>Joshua, Josh</item> + <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> + <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> + <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> + <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> + <item>Kenneth, Ken</item> + <item>Kevin, Kev</item> + <item>Laura, Lauri, Laurie</item> + <item>Lauren, Lauri, Laurie</item> + <item>Laurence, Larry, Lauri, Laurie</item> + <item>Lawrence, Larry, Lauri, Laurie</item> + <item>Leonard, Leo, Len, Lenny</item> + <item>Leopold, Leo, Len, Lenny</item> + <item>Madeline, Maddie, Maddy</item> + <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item> + <item>Matthew, Matt, Mattie</item> + <item>Maureen, Mo</item> + <item>Maurice, Mo</item> + <item>Megan, Meg</item> + <item>Michael, Mickey, Mick, Mike, Mikey</item> + <item>Morris, Mo</item> + <item>Nancy, Nan</item> + <item>Nathan, Nat, Nate</item> + <item>Nathaniel, Nat, Nate</item> + <item>Nicholas, Nick</item> + <item>Pamela, Pam</item> + <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item> + <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item> + <item>Peter, Pete</item> + <item>Raymond, Ray</item> + <item>Philip, Phil</item> + <item>Rebecca, Becca</item> + <item>Richard, Rick, Rich, Dick</item> + <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item> + <item>Roberta, Bobbie</item> + <item>Rodney. Rod</item> + <item>Ronald, Ron, Ronnie</item> + <item>Rosemary, Rosie, Rose</item> + <item>Russell, Russ, Rusty</item> + <item>Ryan, Ry</item> + <item>Samantha, Sam</item> + <item>Samuel, Sam, Sammy</item> + <item>Sophia, Sophie</item> + <item>Stephanie, Steph, Stephie</item> + <item>Stephen, Steve</item> + <item>Steven, Steve</item> + <item>Stuart, Stu</item> + <item>Susan, Sue, Susie, Suzie</item> + <item>Suzanne, Sue, Susie, Suzie</item> + <item>Teresa, Terrie, Terry</item> + <item>Theodora, Teddie, Thea, Theo</item> + <item>Theodore, Ted, Teddy, Theo</item> + <item>Thomas, Tom, Thom, Tommy</item> + <item>Timothy, Tim, Timmy</item> + <item>Valerie, Val</item> + <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item> + <item>Victor, Vic</item> + <item>Victoria, Vicky, Vicki, Vickie, Tori</item> + <item>Vincent, Vince, Vin, Vinnie</item> + <item>Vivian, Vivi</item> + <item>Walter, Walt, Wally</item> + <item>Wendy, Wen, Wendel</item> + <item>William, Bill, Billy, Will, Willy, Liam</item> + <item>Yvonna, Vonna</item> + <item>Zachary, Zach, Zack, Zac</item> + </string-array> + <string name="common_name_prefixes"> + 1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR, + GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR, + MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST + </string> + <string name="common_name_suffixes"> + B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA, + MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X + </string> + <string name="common_last_name_prefixes"> + D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON + </string> + <string name="common_name_conjunctions"> + &, AND, OR + </string> +</resources> diff --git a/core/res/res/values/donottranslate-names.xml b/core/res/res/values/donottranslate-names.xml new file mode 100644 index 000000000000..56ae47a62754 --- /dev/null +++ b/core/res/res/values/donottranslate-names.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Various locale-specific string resources for Contacts --> + <string-array name="common_nicknames"></string-array> + <string name="common_name_prefixes"></string> + <string name="common_name_suffixes"></string> + <string name="common_last_name_prefixes"></string> + <string name="common_name_conjunctions"></string> +</resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 815b767372aa..22f9136c2e27 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1923,157 +1923,6 @@ <!-- This string appears (on two lines) when you type a number into contacts search, to let you create a contact whose phone number is the number you typed. The first line will be in bigger type than the second. --> <string name="create_contact_using">Create contact\nusing <xliff:g id="number" example="555">%s</xliff:g></string> - <!-- various string resources for Contacts --> - <string-array name="common_nicknames"> - <item>Albert, Al, Bert, Bertie</item> - <item>Alexander, Al, Alex, Lex, Sasha</item> - <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item> - <item>Alice, Allie, Ally</item> - <item>Alison, Allie, Ally</item> - <item>Allison, Allie, Ally</item> - <item>Amanda, Mandi, Mandy</item> - <item>Andrea, Andie</item> - <item>Andrew, Andy, Drew</item> - <item>Anthony, Tony, Toni, Tone</item> - <item>Arthur, Art, Arty</item> - <item>Barbara, Babs, Barb, Barbie</item> - <item>Benjamin, Ben, Benji, Benny</item> - <item>Bernard, Bern, Bernie</item> - <item>Bertram, Bert, Bertie</item> - <item>Bradly, Brad</item> - <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item> - <item>Charles, Chuck, Chaz, Charlie, Buck</item> - <item>Christine, Chris, Chrissy, Chrissie</item> - <item>Christopher, Chris</item> - <item>Cynthia, Cindy, Cynth</item> - <item>Daniel, Dan, Danny</item> - <item>David, Dave</item> - <item>Deborah, Deb, Debbie</item> - <item>Dennis, Den, Denny, Dean</item> - <item>Dolores, Dolly</item> - <item>Donald, Don, Donny</item> - <item>Donnatella, Donna</item> - <item>Dorothea, Dot, Dotty</item> - <item>Dorothy, Dot, Dotty</item> - <item>Douglas, Doug</item> - <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item> - <item>Eleanor, Ella, Ellie, Elle</item> - <item>Elisabetta, Betta</item> - <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item> - <item>Emily, Em, Ems, Emmy</item> - <item>Emma, Em, Ems, Emmy</item> - <item>Erica, Rikki, Rikkie, Ricky</item> - <item>Eugene, Gene</item> - <item>Florence, Flo</item> - <item>Frances, Fran, Francie</item> - <item>Francis, Fran, Frank</item> - <item>Frederick, Fred, Freddy</item> - <item>Gabriel, Gabe</item> - <item>Geoffrey, Jeff</item> - <item>Gerald, Gerry</item> - <item>Gerard, Gerry</item> - <item>Gregory, Greg</item> - <item>Harold, Hal, Hank, Harry</item> - <item>Henry, Hal, Hank, Harry</item> - <item>Herbert, Bert, Bertie</item> - <item>Irving, Irv</item> - <item>Isabella, Isa, Izzy</item> - <item>Jacob, Jake</item> - <item>Jacqueline, Jackie</item> - <item>James, Jim, Jimmy, Jamie, Jock</item> - <item>Janet, Jan</item> - <item>Janice, Jan</item> - <item>Jason, Jay</item> - <item>Jefferson, Jeff</item> - <item>Jeffrey, Jeff</item> - <item>Jennifer, Jen, Jenny</item> - <item>Jerome, Jerry</item> - <item>Jessica, Jessie</item> - <item>John, Jack, Jacky, Johnny, Jon</item> - <item>Jonathan, Jon, John</item> - <item>Joseph, Joe, Joey</item> - <item>Joshua, Josh</item> - <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> - <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> - <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> - <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item> - <item>Kenneth, Ken</item> - <item>Kevin, Kev</item> - <item>Laura, Lauri, Laurie</item> - <item>Lauren, Lauri, Laurie</item> - <item>Laurence, Larry, Lauri, Laurie</item> - <item>Lawrence, Larry, Lauri, Laurie</item> - <item>Leonard, Leo, Len, Lenny</item> - <item>Leopold, Leo, Len, Lenny</item> - <item>Madeline, Maddie, Maddy</item> - <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item> - <item>Matthew, Matt, Mattie</item> - <item>Maureen, Mo</item> - <item>Maurice, Mo</item> - <item>Megan, Meg</item> - <item>Michael, Mickey, Mick, Mike, Mikey</item> - <item>Morris, Mo</item> - <item>Nancy, Nan</item> - <item>Nathan, Nat, Nate</item> - <item>Nathaniel, Nat, Nate</item> - <item>Nicholas, Nick</item> - <item>Pamela, Pam</item> - <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item> - <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item> - <item>Peter, Pete</item> - <item>Raymond, Ray</item> - <item>Philip, Phil</item> - <item>Rebecca, Becca</item> - <item>Richard, Rick, Rich, Dick</item> - <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item> - <item>Roberta, Bobbie</item> - <item>Rodney. Rod</item> - <item>Ronald, Ron, Ronnie</item> - <item>Rosemary, Rosie, Rose</item> - <item>Russell, Russ, Rusty</item> - <item>Ryan, Ry</item> - <item>Samantha, Sam</item> - <item>Samuel, Sam, Sammy</item> - <item>Sophia, Sophie</item> - <item>Stephanie, Steph, Stephie</item> - <item>Stephen, Steve</item> - <item>Steven, Steve</item> - <item>Stuart, Stu</item> - <item>Susan, Sue, Susie, Suzie</item> - <item>Suzanne, Sue, Susie, Suzie</item> - <item>Teresa, Terrie, Terry</item> - <item>Theodora, Teddie, Thea, Theo</item> - <item>Theodore, Ted, Teddy, Theo</item> - <item>Thomas, Tom, Thom, Tommy</item> - <item>Timothy, Tim, Timmy</item> - <item>Valerie, Val</item> - <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item> - <item>Victor, Vic</item> - <item>Victoria, Vicky, Vicki, Vickie, Tori</item> - <item>Vincent, Vince, Vin, Vinnie</item> - <item>Vivian, Vivi</item> - <item>Walter, Walt, Wally</item> - <item>Wendy, Wen, Wendel</item> - <item>William, Bill, Billy, Will, Willy, Liam</item> - <item>Yvonna, Vonna</item> - <item>Zachary, Zach, Zack, Zac</item> - </string-array> - <string name="common_name_prefixes"> - 1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR, - GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR, - MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST - </string> - <string name="common_name_suffixes"> - B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA, - MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X - </string> - <string name="common_last_name_prefixes"> - D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON - </string> - <string name="common_name_conjunctions"> - &, AND, OR - </string> - <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale,wifi-channel sets. This is used at startup to set system defaults by checking the system property ro.carrier for the carrier-id and searching through this array --> <!-- An Array of [[Carrier-ID] --> <!-- [default-locale] --> diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java index 3deca4a17d0a..4f16dc4feb54 100644 --- a/graphics/java/android/graphics/DashPathEffect.java +++ b/graphics/java/android/graphics/DashPathEffect.java @@ -23,13 +23,13 @@ public class DashPathEffect extends PathEffect { * the even indices specifying the "on" intervals, and the odd indices * specifying the "off" intervals. phase is an offset into the intervals * array (mod the sum of all of the intervals). The intervals array - * controlls the width of the dashes. The paint's strokeWidth controlls the - * height of the dashes. + * controls the length of the dashes. The paint's strokeWidth controls the + * thickness of the dashes. * Note: this patheffect only affects drawing with the paint's style is set * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with * style == FILL. * @param intervals array of ON and OFF distances - * @param phase offset before the first ON interval is drawn + * @param phase offset into the intervals array */ public DashPathEffect(float intervals[], float phase) { if (intervals.length < 2) { diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java index 9155da8414af..aab8c212b281 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -16,9 +16,6 @@ package android.renderscript; -import android.util.Config; -import android.util.Log; - import java.lang.reflect.Field; /** @@ -193,9 +190,7 @@ public class Element extends BaseObj { void addEntry(Entry e) { if(mEntries.length >= mEntryCount) { Entry[] en = new Entry[mEntryCount + 8]; - for(int ct=0; ct < mEntries.length; ct++) { - en[ct] = mEntries[ct]; - } + System.arraycopy(mEntries, 0, en, 0, mEntries.length); mEntries = en; } mEntries[mEntryCount] = e; diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h index 3db8a0f76a2b..9ea2775ed162 100644 --- a/include/media/mediametadataretriever.h +++ b/include/media/mediametadataretriever.h @@ -52,6 +52,7 @@ enum { METADATA_KEY_VIDEO_FORMAT = 18, METADATA_KEY_VIDEO_HEIGHT = 19, METADATA_KEY_VIDEO_WIDTH = 20, + METADATA_KEY_WRITER = 21, // Add more here... }; diff --git a/include/ui/Surface.h b/include/ui/Surface.h index 4ff0e4abd807..30ab82f8037a 100644 --- a/include/ui/Surface.h +++ b/include/ui/Surface.h @@ -146,16 +146,16 @@ public: static bool isValid(const sp<Surface>& surface) { return (surface != 0) && surface->isValid(); } - bool isValid() { - return mToken>=0 && mClient!=0; - } + static bool isSameSurface( const sp<Surface>& lhs, const sp<Surface>& rhs); - SurfaceID ID() const { return mToken; } - uint32_t getFlags() const { return mFlags; } - uint32_t getIdentity() const { return mIdentity; } + bool isValid(); + SurfaceID ID() const { return mToken; } + uint32_t getFlags() const { return mFlags; } + uint32_t getIdentity() const { return mIdentity; } + // the lock/unlock APIs must be used from the same thread status_t lock(SurfaceInfo* info, bool blocking = true); status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true); status_t unlockAndPost(); @@ -175,14 +175,18 @@ private: friend class SurfaceComposerClient; friend class SurfaceControl; + // camera and camcorder need access to the ISurface binder interface for preview friend class Camera; friend class MediaRecorder; // mediaplayer needs access to ISurface for display friend class MediaPlayer; - friend class Test; friend class IOMX; - const sp<ISurface>& getISurface() const { return mSurface; } + // this is just to be able to write some unit tests + friend class Test; + + sp<SurfaceComposerClient> getClient() const; + sp<ISurface> getISurface() const; status_t getBufferLocked(int index, int usage); @@ -210,24 +214,38 @@ private: status_t queueBuffer(const sp<SurfaceBuffer>& buffer); - alloc_device_t* mAllocDevice; + void setUsage(uint32_t reqUsage); + + // constants sp<SurfaceComposerClient> mClient; sp<ISurface> mSurface; - sp<SurfaceBuffer> mBuffers[2]; - sp<SurfaceBuffer> mLockedBuffer; SurfaceID mToken; uint32_t mIdentity; - uint32_t mWidth; - uint32_t mHeight; - uint32_t mUsage; PixelFormat mFormat; uint32_t mFlags; + BufferMapper& mBufferMapper; + + // protected by mSurfaceLock + Rect mSwapRectangle; + uint32_t mUsage; + bool mUsageChanged; + + // protected by mSurfaceLock. These are also used from lock/unlock + // but in that case, they must be called form the same thread. + sp<SurfaceBuffer> mBuffers[2]; mutable Region mDirtyRegion; - mutable Region mOldDirtyRegion; mutable uint8_t mBackbufferIndex; + + // must be used from the lock/unlock thread + sp<SurfaceBuffer> mLockedBuffer; + mutable Region mOldDirtyRegion; + + // query() must be called from dequeueBuffer() thread + uint32_t mWidth; + uint32_t mHeight; + + // Inherently thread-safe mutable Mutex mSurfaceLock; - Rect mSwapRectangle; - BufferMapper& mBufferMapper; }; }; // namespace android diff --git a/libs/rs/java/Galaxy/Android.mk b/libs/rs/java/Galaxy/Android.mk new file mode 100644 index 000000000000..0884e1871997 --- /dev/null +++ b/libs/rs/java/Galaxy/Android.mk @@ -0,0 +1,25 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, src) +#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript + +LOCAL_PACKAGE_NAME := GalaxyRS + +include $(BUILD_PACKAGE) diff --git a/libs/rs/java/Galaxy/AndroidManifest.xml b/libs/rs/java/Galaxy/AndroidManifest.xml new file mode 100644 index 000000000000..6da1e0fb1a9a --- /dev/null +++ b/libs/rs/java/Galaxy/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.galaxy.rs"> + + <application android:label="GalaxyRS"> + + <activity + android:screenOrientation="portrait" + android:name="Galaxy" + android:theme="@android:style/Theme.NoTitleBar"> + + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + </activity> + + </application> + +</manifest> diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png b/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png Binary files differnew file mode 100644 index 000000000000..fbaaafb2ce74 --- /dev/null +++ b/libs/rs/java/Galaxy/res/drawable-hdpi/flares.png diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png b/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png Binary files differnew file mode 100644 index 000000000000..9d5a795cdc78 --- /dev/null +++ b/libs/rs/java/Galaxy/res/drawable-hdpi/light1.png diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/light2.png b/libs/rs/java/Galaxy/res/drawable-hdpi/light2.png Binary files differnew file mode 100644 index 000000000000..86a6d2e141da --- /dev/null +++ b/libs/rs/java/Galaxy/res/drawable-hdpi/light2.png diff --git a/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg b/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg Binary files differnew file mode 100644 index 000000000000..b61f6a3de5dd --- /dev/null +++ b/libs/rs/java/Galaxy/res/drawable-hdpi/space.jpg diff --git a/libs/rs/java/Galaxy/res/raw/galaxy.c b/libs/rs/java/Galaxy/res/raw/galaxy.c new file mode 100644 index 000000000000..ab82b5846891 --- /dev/null +++ b/libs/rs/java/Galaxy/res/raw/galaxy.c @@ -0,0 +1,181 @@ +// 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. + +#pragma version(1) +#pragma stateVertex(PVBackground) +#pragma stateFragment(PFBackground) +#pragma stateFragmentStore(PFSBackground) + +#define RSID_STATE 0 +#define RSID_FRAME_COUNT 0 +#define RSID_WIDTH 1 +#define RSID_HEIGHT 2 +#define RSID_PARTICLES_COUNT 3 +#define RSID_GALAXY_RADIUS 4 + +#define RSID_PARTICLES 1 + +#define PARTICLE_STRUCT_FIELDS_COUNT 7 +#define PARTICLE_STRUCT_ANGLE 0 +#define PARTICLE_STRUCT_DISTANCE 1 +#define PARTICLE_STRUCT_SPEED 2 +#define PARTICLE_STRUCT_Z 3 +#define PARTICLE_STRUCT_RADIUS 4 +#define PARTICLE_STRUCT_U1 5 +#define PARTICLE_STRUCT_U2 6 + +#define RSID_PARTICLES_BUFFER 2 +#define PARTICLE_BUFFER_COMPONENTS_COUNT 6 + +#define PARTICLES_TEXTURES_COUNT 2 + +#define ELLIPSE_RATIO 0.86f +#define ELLIPSE_TWIST 0.02333333333f + +void drawSpace(int width, int height) { + bindTexture(NAMED_PFBackground, 0, NAMED_TSpace); + drawQuadTexCoords( + 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, + width, 0.0f, 0.0f, + 2.0f, 1.0f, + width, height, 0.0f, + 2.0f, 0.0f, + 0.0f, height, 0.0f, + 0.0f, 0.0f); +} + +void drawLights(int width, int height) { + bindProgramFragment(NAMED_PFBackground); + bindProgramFragmentStore(NAMED_PFSLights); + + float x = (width - 512.0f) / 2.0f; + float y = (height - 512.0f) / 2.0f; + + bindTexture(NAMED_PFBackground, 0, NAMED_TLight1); + drawQuad(x + 512.0f, y , 0.0f, + x , y , 0.0f, + x , y + 512.0f, 0.0f, + x + 512.0f, y + 512.0f, 0.0f); + + bindTexture(NAMED_PFBackground, 0, NAMED_TLight2); + drawQuad(x + 512.0f, y , 0.0f, + x , y , 0.0f, + x , y + 512.0f, 0.0f, + x + 512.0f, y + 512.0f, 0.0f); +} + +void drawParticle(int index, int bufferIndex, int width, int height, int radius) { + float *particle = loadArrayF(RSID_PARTICLES, index); + + float distance = particle[PARTICLE_STRUCT_DISTANCE]; + float angle = particle[PARTICLE_STRUCT_ANGLE]; + float speed = particle[PARTICLE_STRUCT_SPEED]; + float r = particle[PARTICLE_STRUCT_RADIUS]; + + int red; + int green; + int blue; + + if (distance < radius / 3.0f) { + red = 220 + (distance / (float) radius) * 35; + green = 220; + blue = 220; + } else { + red = 180; + green = 180; + blue = clamp(140 + (distance / (float) radius) * 115, 140, 255); + } + + int color = 0xFF000000 | red | green << 8 | blue << 16; + + float a = angle + speed * (0.5f + (0.5f * radius / distance)); + float x = distance * sinf(a); + float y = distance * cosf(a) * ELLIPSE_RATIO; + float z = distance * ELLIPSE_TWIST; + float s = cosf(z); + float t = sinf(z); + + float sX = t * x + s * y + width / 2.0f; + float sY = s * x - t * y + height / 2.0f; + float sZ = particle[PARTICLE_STRUCT_Z]; + + float u1 = particle[PARTICLE_STRUCT_U1]; + float u2 = particle[PARTICLE_STRUCT_U2]; + + // lower left vertex of the particle's triangle + storeI32(RSID_PARTICLES_BUFFER, bufferIndex, color); // ABGR + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 1, sX - r); // X + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 2, sY + r); // Y + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 3, sZ); // Z + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 4, u1); // S + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 5, 1.0f); // T + + // lower right vertex of the particle's triangle + bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT; + storeI32(RSID_PARTICLES_BUFFER, bufferIndex, color); + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 1, sX + r); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 2, sY + r); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 3, sZ); + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 4, u2); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 5, 1.0f); + + // upper middle vertex of the particle's triangle + bufferIndex += PARTICLE_BUFFER_COMPONENTS_COUNT; + storeI32(RSID_PARTICLES_BUFFER, bufferIndex, color); + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 1, sX); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 2, sY - r); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 3, sZ); + + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 4, u1 + (u2 - u1) / 2.0f); + storeF(RSID_PARTICLES_BUFFER, bufferIndex + 5, 0.0f); + + particle[PARTICLE_STRUCT_ANGLE] = a; +} + +void drawParticles(int width, int height) { + bindProgramFragment(NAMED_PFLighting); + bindTexture(NAMED_PFLighting, 0, NAMED_TFlares); + + int radius = loadI32(RSID_STATE, RSID_GALAXY_RADIUS); + int particlesCount = loadI32(RSID_STATE, RSID_PARTICLES_COUNT); + int count = particlesCount * PARTICLE_STRUCT_FIELDS_COUNT; + + int i = 0; + int bufferIndex = 0; + for ( ; i < count; i += PARTICLE_STRUCT_FIELDS_COUNT) { + drawParticle(i, bufferIndex, width, height, radius); + // each particle is a triangle (3 vertices) of 6 properties (ABGR, X, Y, Z, S, T) + bufferIndex += 3 * PARTICLE_BUFFER_COMPONENTS_COUNT; + } + + uploadToBufferObject(NAMED_BParticles); + drawSimpleMeshRange(NAMED_MParticles, 0, particlesCount * 3); +} + +int main(int index) { + int width = loadI32(RSID_STATE, RSID_WIDTH); + int height = loadI32(RSID_STATE, RSID_HEIGHT); + + drawSpace(width, height); + drawParticles(width, height); + drawLights(width, height); + + return 1; +} diff --git a/core/java/android/accounts/Future2Callback.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java index 7ef0c94741d0..27d333c90804 100644 --- a/core/java/android/accounts/Future2Callback.java +++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/Galaxy.java @@ -13,8 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.accounts; -public interface Future2Callback { - void run(Future2 future); +package com.android.galaxy.rs; + +import android.app.Activity; +import android.os.Bundle; + +public class Galaxy extends Activity { + private GalaxyView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mView = new GalaxyView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + super.onResume(); + mView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mView.onPause(); + + Runtime.getRuntime().exit(0); + } }
\ No newline at end of file diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java new file mode 100644 index 000000000000..33de229b9595 --- /dev/null +++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyRS.java @@ -0,0 +1,332 @@ +/* + * 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.galaxy.rs; + +import android.content.res.Resources; +import android.renderscript.RenderScript; +import android.renderscript.ScriptC; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.Allocation; +import android.renderscript.Sampler; +import android.renderscript.Element; +import android.renderscript.SimpleMesh; +import android.renderscript.Primitive; +import static android.renderscript.Sampler.Value.LINEAR; +import static android.renderscript.Sampler.Value.CLAMP; +import static android.renderscript.Sampler.Value.WRAP; +import static android.renderscript.ProgramStore.DepthFunc.*; +import static android.renderscript.ProgramStore.BlendDstFunc; +import static android.renderscript.ProgramStore.BlendSrcFunc; +import static android.renderscript.ProgramFragment.EnvMode.*; +import static android.renderscript.Element.*; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import static android.util.MathUtils.*; + +import java.util.TimeZone; + +class GalaxyRS { + private static final int GALAXY_RADIUS = 300; + private static final int PARTICLES_COUNT = 12000; + private static final float GALAXY_HEIGHT = 0.1f; + + private static final int RSID_STATE = 0; + private static final int RSID_STATE_FRAMECOUNT = 0; + private static final int RSID_STATE_WIDTH = 1; + private static final int RSID_STATE_HEIGHT = 2; + private static final int RSID_STATE_PARTICLES_COUNT = 3; + private static final int RSID_STATE_GALAXY_RADIUS = 4; + + private static final int TEXTURES_COUNT = 4; + private static final int PARTICLES_TEXTURES_COUNT = 2; + private static final int RSID_TEXTURE_SPACE = 0; + private static final int RSID_TEXTURE_LIGHT1 = 1; + private static final int RSID_TEXTURE_LIGHT2 = 2; + private static final int RSID_TEXTURE_FLARES = 3; + + private static final int RSID_PARTICLES = 1; + private static final int PARTICLE_STRUCT_FIELDS_COUNT = 7; + private static final int PARTICLE_STRUCT_ANGLE = 0; + private static final int PARTICLE_STRUCT_DISTANCE = 1; + private static final int PARTICLE_STRUCT_SPEED = 2; + private static final int PARTICLE_STRUCT_Z = 3; + private static final int PARTICLE_STRUCT_RADIUS = 4; + private static final int PARTICLE_STRUCT_U1 = 5; + private static final int PARTICLE_STRUCT_U2 = 6; + + private static final int RSID_PARTICLES_BUFFER = 2; + + private Resources mResources; + private RenderScript mRS; + + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + + private final int mWidth; + private final int mHeight; + + private ScriptC mScript; + private Sampler mSampler; + private Sampler mLightSampler; + private ProgramFragment mPfBackground; + private ProgramFragment mPfLighting; + private ProgramStore mPfsBackground; + private ProgramStore mPfsLights; + private ProgramVertex mPvBackground; + private ProgramVertex.MatrixAllocation mPvOrthoAlloc; + + private Allocation[] mTextures; + + private Allocation mState; + private Allocation mParticles; + private Allocation mParticlesBuffer; + private SimpleMesh mParticlesMesh; + + public GalaxyRS(int width, int height) { + mWidth = width; + mHeight = height; + mOptionsARGB.inScaled = false; + mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; + } + + public void init(RenderScript rs, Resources res) { + mRS = rs; + mResources = res; + initRS(); + } + + public void destroy() { + mScript.destroy(); + mSampler.destroy(); + mLightSampler.destroy(); + mPfBackground.destroy(); + mPfsBackground.destroy(); + mPvBackground.destroy(); + mPvOrthoAlloc.mAlloc.destroy(); + for (Allocation a : mTextures) { + a.destroy(); + } + mState.destroy(); + mPfLighting.destroy(); + mParticles.destroy(); + mPfsLights.destroy(); + mParticlesMesh.destroy(); + mParticlesBuffer.destroy(); + } + + @Override + protected void finalize() throws Throwable { + try { + destroy(); + } finally { + super.finalize(); + } + } + + private void initRS() { + createProgramVertex(); + createProgramFragmentStore(); + createProgramFragment(); + createScriptStructures(); + loadTextures(); + + ScriptC.Builder sb = new ScriptC.Builder(mRS); + sb.setScript(mResources, R.raw.galaxy); + sb.setRoot(true); + mScript = sb.create(); + mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); + mScript.setTimeZone(TimeZone.getDefault().getID()); + + mScript.bindAllocation(mState, RSID_STATE); + mScript.bindAllocation(mParticles, RSID_PARTICLES); + mScript.bindAllocation(mParticlesBuffer, RSID_PARTICLES_BUFFER); + + mRS.contextBindRootScript(mScript); + } + + private void createScriptStructures() { + createState(); + createParticles(); + createParticlesMesh(); + } + + private void createParticlesMesh() { + final Element.Builder elementBuilder = new Element.Builder(mRS); + elementBuilder.add(Element.DataType.UNSIGNED, Element.DataKind.RED, true, 8); + elementBuilder.add(Element.DataType.UNSIGNED, Element.DataKind.GREEN, true, 8); + elementBuilder.add(Element.DataType.UNSIGNED, Element.DataKind.BLUE, true, 8); + elementBuilder.add(Element.DataType.UNSIGNED, Element.DataKind.ALPHA, true, 8); + elementBuilder.add(Element.DataType.FLOAT, Element.DataKind.X, false, 32); + elementBuilder.add(Element.DataType.FLOAT, Element.DataKind.Y, false, 32); + elementBuilder.add(Element.DataType.FLOAT, Element.DataKind.Z, false, 32); + elementBuilder.add(Element.DataType.FLOAT, Element.DataKind.S, false, 32); + elementBuilder.add(Element.DataType.FLOAT, Element.DataKind.T, false, 32); + final Element vertexElement = elementBuilder.create(); + + final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS); + final int vertexSlot = meshBuilder.addVertexType(vertexElement, PARTICLES_COUNT * 3); + meshBuilder.setPrimitive(Primitive.TRIANGLE); + mParticlesMesh = meshBuilder.create(); + mParticlesMesh.setName("MParticles"); + + mParticlesBuffer = mParticlesMesh.createVertexAllocation(vertexSlot); + mParticlesBuffer.setName("BParticles"); + mParticlesMesh.bindVertexAllocation(mParticlesBuffer, 0); + } + + private void createParticles() { + final float[] particles = new float[PARTICLES_COUNT * PARTICLE_STRUCT_FIELDS_COUNT]; + mParticles = Allocation.createSized(mRS, USER_FLOAT, particles.length); + for (int i = 0; i < particles.length; i += PARTICLE_STRUCT_FIELDS_COUNT) { + createParticle(particles, i); + } + mParticles.data(particles); + } + + private void createState() { + final int[] data = new int[5]; + + mState = Allocation.createSized(mRS, USER_I32, data.length); + data[RSID_STATE_FRAMECOUNT] = 0; + data[RSID_STATE_WIDTH] = mWidth; + data[RSID_STATE_HEIGHT] = mHeight; + data[RSID_STATE_PARTICLES_COUNT] = PARTICLES_COUNT; + data[RSID_STATE_GALAXY_RADIUS] = GALAXY_RADIUS; + mState.data(data); + } + + @SuppressWarnings({"PointlessArithmeticExpression"}) + private void createParticle(float[] particles, int index) { + int sprite = random(PARTICLES_TEXTURES_COUNT); + float d = abs(randomGauss()) * GALAXY_RADIUS / 2.0f; + + particles[index + PARTICLE_STRUCT_ANGLE] = random(0.0f, (float) (Math.PI * 2.0)); + particles[index + PARTICLE_STRUCT_DISTANCE] = d; + particles[index + PARTICLE_STRUCT_SPEED] = random(0.0015f, 0.0025f); + particles[index + PARTICLE_STRUCT_Z] = randomGauss() * GALAXY_HEIGHT * + (GALAXY_RADIUS - d) / (float) GALAXY_RADIUS; + particles[index + PARTICLE_STRUCT_RADIUS] = random(3.0f, 7.5f); + particles[index + PARTICLE_STRUCT_U1] = sprite / (float) PARTICLES_TEXTURES_COUNT; + particles[index + PARTICLE_STRUCT_U2] = (sprite + 1) / (float) PARTICLES_TEXTURES_COUNT; + } + + private static float randomGauss() { + float x1; + float x2; + float w; + + do { + x1 = 2.0f * random(0.0f, 1.0f) - 1.0f; + x2 = 2.0f * random(0.0f, 1.0f) - 1.0f; + w = x1 * x1 + x2 * x2; + } while (w >= 1.0f); + + w = (float) Math.sqrt(-2.0 * log(w) / w); + return x1 * w; + } + + private void loadTextures() { + mTextures = new Allocation[TEXTURES_COUNT]; + + final Allocation[] textures = mTextures; + textures[RSID_TEXTURE_SPACE] = loadTexture(R.drawable.space, "TSpace"); + textures[RSID_TEXTURE_LIGHT1] = loadTextureARGB(R.drawable.light1, "TLight1"); + textures[RSID_TEXTURE_LIGHT2] = loadTextureARGB(R.drawable.light2, "TLight2"); + textures[RSID_TEXTURE_FLARES] = loadTextureARGB(R.drawable.flares, "TFlares"); + + final int count = textures.length; + for (int i = 0; i < count; i++) { + final Allocation texture = textures[i]; + texture.uploadToTexture(0); + } + } + + private Allocation loadTexture(int id, String name) { + final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, + id, RGB_565, false); + allocation.setName(name); + return allocation; + } + + private Allocation loadTextureARGB(int id, String name) { + Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); + final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false); + allocation.setName(name); + return allocation; + } + + private void createProgramFragment() { + Sampler.Builder sampleBuilder = new Sampler.Builder(mRS); + sampleBuilder.setMin(LINEAR); + sampleBuilder.setMag(LINEAR); + sampleBuilder.setWrapS(WRAP); + sampleBuilder.setWrapT(WRAP); + mSampler = sampleBuilder.create(); + + ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null); + builder.setTexEnable(true, 0); + builder.setTexEnvMode(REPLACE, 0); + mPfBackground = builder.create(); + mPfBackground.setName("PFBackground"); + mPfBackground.bindSampler(mSampler, 0); + + sampleBuilder = new Sampler.Builder(mRS); + sampleBuilder.setMin(LINEAR); + sampleBuilder.setMag(LINEAR); + sampleBuilder.setWrapS(CLAMP); + sampleBuilder.setWrapT(CLAMP); + mLightSampler = sampleBuilder.create(); + + builder = new ProgramFragment.Builder(mRS, null, null); + builder.setTexEnable(true, 0); + builder.setTexEnvMode(MODULATE, 0); + mPfLighting = builder.create(); + mPfLighting.setName("PFLighting"); + mPfLighting.bindSampler(mLightSampler, 0); + } + + private void createProgramFragmentStore() { + ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null); + builder.setDepthFunc(ALWAYS); + builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnable(false); + builder.setDepthMask(true); + mPfsBackground = builder.create(); + mPfsBackground.setName("PFSBackground"); + + builder = new ProgramStore.Builder(mRS, null, null); + builder.setDepthFunc(ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnable(false); + builder.setDepthMask(true); + mPfsLights = builder.create(); + mPfsLights.setName("PFSLights"); + } + + private void createProgramVertex() { + mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS); + //mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight); + mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight); + + ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null); + builder.setTextureMatrixEnable(true); + mPvBackground = builder.create(); + mPvBackground.bindAllocation(mPvOrthoAlloc); + mPvBackground.setName("PVBackground"); + } +} diff --git a/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java new file mode 100644 index 000000000000..341293bd9a7c --- /dev/null +++ b/libs/rs/java/Galaxy/src/com/android/galaxy/rs/GalaxyView.java @@ -0,0 +1,45 @@ +/* + * 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.galaxy.rs; + +import android.content.Context; +import android.view.SurfaceHolder; +import android.renderscript.RenderScript; +import android.renderscript.RSSurfaceView; + +class GalaxyView extends RSSurfaceView { + private GalaxyRS mRender; + + public GalaxyView(Context context) { + super(context); + setFocusable(true); + setFocusableInTouchMode(true); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + + RenderScript RS = createRenderScript(); + mRender = new GalaxyRS(w, h); + mRender.init(RS, getResources()); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + if (mRender != null) mRender.destroy(); + } +} diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index ac4bf7ba4f08..6f92515c32cc 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -596,7 +596,12 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions) Point Layer::getPhysicalSize() const { sp<const Buffer> front(frontBuffer().getBuffer()); - return Point(front->getWidth(), front->getHeight()); + Point size(front->getWidth(), front->getHeight()); + if ((size.x | size.y) == 0) { + // if we don't have a buffer yet, just use the state's size. + size = LayerBase::getPhysicalSize(); + } + return size; } void Layer::unlockPageFlip( diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index 2b6905f33fc2..f6792c459597 100644 --- a/libs/ui/Surface.cpp +++ b/libs/ui/Surface.cpp @@ -382,9 +382,9 @@ sp<Surface> SurfaceControl::getSurface() const Surface::Surface(const sp<SurfaceControl>& surface) : mClient(surface->mClient), mSurface(surface->mSurface), mToken(surface->mToken), mIdentity(surface->mIdentity), - mWidth(surface->mWidth), mHeight(surface->mHeight), mFormat(surface->mFormat), mFlags(surface->mFlags), - mBufferMapper(BufferMapper::get()) + mBufferMapper(BufferMapper::get()), + mWidth(surface->mWidth), mHeight(surface->mHeight) { init(); } @@ -426,9 +426,9 @@ void Surface::init() const_cast<uint32_t&>(android_native_window_t::flags) = 0; // be default we request a hardware surface mUsage = GRALLOC_USAGE_HW_RENDER; + mUsageChanged = true; } - Surface::~Surface() { // this is a client-side operation, the surface is destroyed, unmap @@ -446,11 +446,24 @@ Surface::~Surface() IPCThreadState::self()->flushCommands(); } +sp<SurfaceComposerClient> Surface::getClient() const { + return mClient; +} + +sp<ISurface> Surface::getISurface() const { + return mSurface; +} + +bool Surface::isValid() { + return mToken>=0 && mClient!=0; +} + status_t Surface::validate(per_client_cblk_t const* cblk) const { + sp<SurfaceComposerClient> client(getClient()); if (mToken<0 || mClient==0) { LOGE("invalid token (%d, identity=%u) or client (%p)", - mToken, mIdentity, mClient.get()); + mToken, mIdentity, client.get()); return NO_INIT; } if (cblk == 0) { @@ -477,6 +490,7 @@ bool Surface::isSameSurface( { if (lhs == 0 || rhs == 0) return false; + return lhs->mSurface->asBinder() == rhs->mSurface->asBinder(); } @@ -532,10 +546,9 @@ status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer) { android_native_buffer_t* out; status_t err = dequeueBuffer(&out); - *buffer = SurfaceBuffer::getSelf(out); - // reset the width/height with the what we get from the buffer - mWidth = uint32_t(out->width); - mHeight = uint32_t(out->height); + if (err == NO_ERROR) { + *buffer = SurfaceBuffer::getSelf(out); + } return err; } @@ -557,7 +570,8 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) Mutex::Autolock _l(mSurfaceLock); - per_client_cblk_t* const cblk = mClient->mControl; + sp<SurfaceComposerClient> client(getClient()); + per_client_cblk_t* const cblk = client->mControl; status_t err = validate(cblk); if (err != NO_ERROR) return err; @@ -572,14 +586,17 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) mBackbufferIndex = backIdx; layer_cblk_t* const lcblk = &(cblk->layers[index]); - volatile const surface_info_t* const back = lcblk->surface + backIdx; - if (back->flags & surface_info_t::eNeedNewBuffer) { + if ((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged) { + mUsageChanged = false; err = getBufferLocked(backIdx, mUsage); } if (err == NO_ERROR) { const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]); + // reset the width/height with the what we get from the buffer + mWidth = uint32_t(backBuffer->width); + mHeight = uint32_t(backBuffer->height); mDirtyRegion.set(backBuffer->width, backBuffer->height); *buffer = backBuffer.get(); } @@ -591,7 +608,8 @@ int Surface::lockBuffer(android_native_buffer_t* buffer) { Mutex::Autolock _l(mSurfaceLock); - per_client_cblk_t* const cblk = mClient->mControl; + sp<SurfaceComposerClient> client(getClient()); + per_client_cblk_t* const cblk = client->mControl; status_t err = validate(cblk); if (err != NO_ERROR) return err; @@ -604,7 +622,8 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) { Mutex::Autolock _l(mSurfaceLock); - per_client_cblk_t* const cblk = mClient->mControl; + sp<SurfaceComposerClient> client(getClient()); + per_client_cblk_t* const cblk = client->mControl; status_t err = validate(cblk); if (err != NO_ERROR) return err; @@ -620,7 +639,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) uint32_t newstate = cblk->unlock_layer_and_post(size_t(index)); if (!(newstate & eNextFlipPending)) - mClient->signalServer(); + client->signalServer(); return NO_ERROR; } @@ -646,7 +665,7 @@ int Surface::perform(int operation, va_list args) int res = NO_ERROR; switch (operation) { case NATIVE_WINDOW_SET_USAGE: - mUsage = va_arg(args, int); + setUsage( va_arg(args, int) ); break; default: res = NAME_NOT_FOUND; @@ -655,6 +674,15 @@ int Surface::perform(int operation, va_list args) return res; } +void Surface::setUsage(uint32_t reqUsage) +{ + Mutex::Autolock _l(mSurfaceLock); + if (mUsage != reqUsage) { + mUsageChanged = true; + mUsage = reqUsage; + } +} + // ---------------------------------------------------------------------------- status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -663,11 +691,9 @@ status_t Surface::lock(SurfaceInfo* info, bool blocking) { status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) { - // FIXME: needs some locking here - // we're intending to do software rendering from this point - mUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; - + setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + sp<SurfaceBuffer> backBuffer; status_t err = dequeueBuffer(&backBuffer); if (err == NO_ERROR) { @@ -679,7 +705,8 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) Region scratch(bounds); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); - per_client_cblk_t* const cblk = mClient->mControl; + sp<SurfaceComposerClient> client(getClient()); + per_client_cblk_t* const cblk = client->mControl; layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]); volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex; if (back->flags & surface_info_t::eBufferDirty) { @@ -725,8 +752,6 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) status_t Surface::unlockAndPost() { - // FIXME: needs some locking here - if (mLockedBuffer == 0) return BAD_VALUE; @@ -753,13 +778,17 @@ void Surface::_send_dirty_region( } void Surface::setSwapRectangle(const Rect& r) { + Mutex::Autolock _l(mSurfaceLock); mSwapRectangle = r; } status_t Surface::getBufferLocked(int index, int usage) { + sp<ISurface> s(mSurface); + if (s == 0) return NO_INIT; + status_t err = NO_MEMORY; - sp<SurfaceBuffer> buffer = mSurface->getBuffer(usage); + sp<SurfaceBuffer> buffer = s->getBuffer(usage); LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL"); if (buffer != 0) { sp<SurfaceBuffer>& currentBuffer(mBuffers[index]); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 60fc0e048b0d..16bf8a2dd494 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -153,20 +153,6 @@ public class AudioManager { @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; - /** @hide Maximum volume index values for audio streams */ - public static final int[] MAX_STREAM_VOLUME = new int[] { - 6, // STREAM_VOICE_CALL - 8, // STREAM_SYSTEM - 8, // STREAM_RING - 16, // STREAM_MUSIC - 8, // STREAM_ALARM - 8, // STREAM_NOTIFICATION - 16, // STREAM_BLUETOOTH_SCO - 8, // STREAM_SYSTEM_ENFORCED - 16, // STREAM_DTMF - 16 // STREAM_TTS - }; - /** @hide Default volume index values for audio streams */ public static final int[] DEFAULT_STREAM_VOLUME = new int[] { 4, // STREAM_VOICE_CALL diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 9afe6a150a7c..5a59712df020 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -44,6 +44,7 @@ import android.provider.Settings; import android.provider.Settings.System; import android.util.Log; import android.view.VolumePanel; +import android.os.SystemProperties; import com.android.internal.telephony.ITelephony; @@ -54,6 +55,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; + /** * The implementation of the volume manager service. * <p> @@ -140,6 +142,19 @@ public class AudioService extends IAudioService.Stub { {4, -1} // FX_FOCUS_RETURN }; + /** @hide Maximum volume index values for audio streams */ + private int[] MAX_STREAM_VOLUME = new int[] { + 6, // STREAM_VOICE_CALL + 8, // STREAM_SYSTEM + 8, // STREAM_RING + 16, // STREAM_MUSIC + 8, // STREAM_ALARM + 8, // STREAM_NOTIFICATION + 16, // STREAM_BLUETOOTH_SCO + 8, // STREAM_SYSTEM_ENFORCED + 16, // STREAM_DTMF + 16 // STREAM_TTS + }; /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings * of another stream: This avoids multiplying the volume settings for hidden * stream types that follow other stream behavior for volume settings @@ -231,6 +246,12 @@ public class AudioService extends IAudioService.Stub { public AudioService(Context context) { mContext = context; mContentResolver = context.getContentResolver(); + + // Intialized volume + MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( + "ro.config.vc_call_vol_steps", + MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); + mVolumePanel = new VolumePanel(context, this); mSettingsObserver = new SettingsObserver(); mMode = AudioSystem.MODE_NORMAL; @@ -249,6 +270,7 @@ public class AudioService extends IAudioService.Stub { intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); context.registerReceiver(mReceiver, intentFilter); + } private void createAudioSystemThread() { @@ -945,7 +967,7 @@ public class AudioService extends IAudioService.Stub { mStreamType = streamType; final ContentResolver cr = mContentResolver; - mIndexMax = AudioManager.MAX_STREAM_VOLUME[streamType]; + mIndexMax = MAX_STREAM_VOLUME[streamType]; mIndex = Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType]); diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 6d7c0ae2facf..d578c8159f1f 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -18,6 +18,9 @@ package android.media; import android.util.Log; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -59,7 +62,7 @@ public class ExifInterface { // The Exif tag names public static final String TAG_ORIENTATION = "Orientation"; - public static final String TAG_DATE_TIME_ORIGINAL = "DateTimeOriginal"; + public static final String TAG_DATETIME = "DateTime"; public static final String TAG_MAKE = "Make"; public static final String TAG_MODEL = "Model"; public static final String TAG_FLASH = "Flash"; @@ -321,6 +324,28 @@ public class ExifInterface { return latlng; } + private static SimpleDateFormat sFormatter = + new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); + + // Returns number of milliseconds since Jan. 1, 1970, midnight GMT. + // Returns -1 if the date time information if not available. + public static long getDateTime(HashMap<String, String> exifData) { + if (exifData == null) { + return -1; + } + + String dateTimeString = exifData.get(ExifInterface.TAG_DATETIME); + if (dateTimeString == null) return -1; + + ParsePosition pos = new ParsePosition(0); + try { + Date date = sFormatter.parse(dateTimeString, pos); + return date.getTime(); + } catch (IllegalArgumentException ex) { + return -1; + } + } + public static float convertRationalLatLonToFloat( String rationalString, String ref) { try { diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index c6a9ae8b23ad..cecf4f818014 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -254,5 +254,6 @@ public class MediaMetadataRetriever public static final int METADATA_KEY_VIDEO_FORMAT = 18; public static final int METADATA_KEY_VIDEO_HEIGHT = 19; public static final int METADATA_KEY_VIDEO_WIDTH = 20; + public static final int METADATA_KEY_WRITER = 21; // Add more here... } diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 71af909c36b4..3d5aae3dbf38 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -396,6 +396,7 @@ public class MediaScanner private String mPath; private long mLastModified; private long mFileSize; + private String mWriter; public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) { @@ -479,6 +480,7 @@ public class MediaScanner mDuration = 0; mPath = path; mLastModified = lastModified; + mWriter = null; return entry; } @@ -593,6 +595,8 @@ public class MediaScanner mTrack = (num * 1000) + (mTrack % 1000); } else if (name.equalsIgnoreCase("duration")) { mDuration = parseSubstring(value, 0, 0); + } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) { + mWriter = value.trim(); } } @@ -716,6 +720,11 @@ public class MediaScanner values.put(Images.Media.LATITUDE, latlng[0]); values.put(Images.Media.LONGITUDE, latlng[1]); } + + long time = ExifInterface.getDateTime(exifData); + if (time != -1) { + values.put(Images.Media.DATE_TAKEN, time); + } } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java index e76967d921e6..3f2bc396e1d0 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java @@ -372,81 +372,81 @@ public class MediaNames { public static final String META_DATA_MP3 [][] = { {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", - "ID3V2.3 Title", "1234", "295", "1"}, + "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", - "ID3V2.3 Title", "1234", "287", "1"}, + "ID3V2.3 Title", "1234", "287", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", "1", "test ID3V1 Album", "test ID3V1 Artist", - null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1"}, + null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null, - null, null, null, null, null, null, "231330", "1"}, + null, null, null, null, null, null, "231330", "1", null}, //The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, - "Blues", "ID3V2.3 Title", "1234", "295", "1"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null, - "Blues", "ID3V2.3 Title", "1234", "295", "1"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1"}, + "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, - "Blues", "ID3V2.3 Title", "1234", "295", "1"}, + "Blues", "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1"}, + "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album", - "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1"}, + "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, - "Blues", "ID3V2.3 Title", null, "295", "1"}, + "Blues", "ID3V2.3 Title", null, "295", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null, - null, null, null, null, null, null, "295", "1"} + null, null, null, null, null, null, "295", "1", null} }; public static final String META_DATA_OTHERS [][] = { {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null, null, null, "20080309T002415.000Z", null, - null, null, "1404928", "2"}, + null, null, "1404928", "2", null}, {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null, null, null, null, null, - null, null, "126540", "1"}, + null, null, "126540", "1", null}, {"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null, null, null, null, null, - null, null, "231180", "1"}, - {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation", + null, null, "231180", "1", null}, + {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", - null, null, "2005", "231180", "1"}, + "13", "Jaws Of Life", "2005", "19815424", "1", "m4a composer"}, {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, null, null, null, "20051220T202015.000Z", - null, null, null, "3771392", "2"}, + null, null, null, "3771392", "2", null}, {"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", - null, null, "2005", "231180", "1"}, - {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda", + null, null, "2005", "231180", "1", null}, + {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda", "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", - "41", "Kung Fu Panda", "2008", "5667840", "2"}, + "41", "Kung Fu Panda", "2008", "5667840", "2", "mp4 composer"}, {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", - null, null, "2005", "231180", "1"}, + null, null, "2005", "231180", "1", null}, {"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg", null, "Suspended Animation", "John Petrucci", - null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, + null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1", null}, {"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null, null, null, null, null, - null, null, null, "224000", "1"}, + null, null, null, "224000", "1", null}, {"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal", "Alien Crime Syndicate", "Alien Crime Syndicate", "wma 9 Composer", "20040521T175729.483Z", - "Rock", "Run for the Money", "2004", "134479", "1"}, + "Rock", "Run for the Money", "2004", "134479", "1", null}, {"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album", "wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z", - "Acid Jazz", "wma 10 Title", "2010", "126574", "1"}, + "Acid Jazz", "wma 10 Title", "2010", "126574", "1", null}, {"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album", null, "wmv 9 Artist ", null, "20051122T155247.540Z", - null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"}, + null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2", null}, {"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album", null, "Hallau Shoots & Company", null, "20020226T170045.891Z", - null, "CODEC Shootout", "1986", "43709", "2"} + null, "CODEC Shootout", "1986", "43709", "2", null} }; //output recorded video diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java index 3715913877e4..1bf4958327fa 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java @@ -36,7 +36,7 @@ public class MediaMetadataTest extends AndroidTestCase { FILE_PATH,CD_TRACK, ALBUM, ARTIST, AUTHOR, COMPOSER, DATE, GENRE, TITLE, - YEAR, DURATION, NUM_TRACKS + YEAR, DURATION, NUM_TRACKS, WRITER } public static enum MP3_TEST_FILE{ @@ -130,8 +130,6 @@ public class MediaMetadataTest extends AndroidTestCase { validateMetatData(non_mp3_test_file.AMRWB.ordinal(), MediaNames.META_DATA_OTHERS); } - //Bug# 1440173 - skip this test case now - @Suppress @MediumTest public static void testM4A1_Metadata() throws Exception { validateMetatData(non_mp3_test_file.M4A1.ordinal(), MediaNames.META_DATA_OTHERS); @@ -254,6 +252,10 @@ public class MediaMetadataTest extends AndroidTestCase { Log.v(TAG, "Track : "+ value); assertEquals(TAG,meta_data_file[fileIndex][meta.NUM_TRACKS.ordinal()], value); + value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER); + Log.v(TAG, "Writer : "+ value); + assertEquals(TAG,meta_data_file[fileIndex][meta.WRITER.ordinal()], value); + retriever.release(); } } diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java index 3cd2cc4a00cc..b854f869aba5 100644 --- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java +++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java @@ -113,7 +113,7 @@ public class SubscribedFeedsIntentService extends IntentService { // TODO(fredq) fix the hardcoded type final Account account = new Account(accountName, "com.google.GAIA"); c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI, - null, where, new String[]{account.mName, account.mType, feed}, null); + null, where, new String[]{account.name, account.type, feed}, null); if (c.getCount() == 0) { Log.w(TAG, "received tickle for non-existent feed: " + "account " + accountName + ", feed " + feed); @@ -171,12 +171,12 @@ public class SubscribedFeedsIntentService extends IntentService { try { ContentValues values = new ContentValues(); for (Account account : accounts) { - values.put(SyncConstValue._SYNC_ACCOUNT, account.mName); - values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.mType); + values.put(SyncConstValue._SYNC_ACCOUNT, account.name); + values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type); contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values, SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?", - new String[] {account.mName, account.mType}); + new String[] {account.name, account.type}); } } catch (SQLiteFullException e) { Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping"); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 1c60058d2d29..72a1192db7cf 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -100,6 +100,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // a process dies private List mFeatureUsers; + private boolean mSystemReady; + private ArrayList<Intent> mDeferredBroadcasts; + private class NetworkAttributes { /** * Class for holding settings read from resources. @@ -820,7 +823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { (newNet == null || !newNet.isAvailable() ? "" : " other=" + newNet.getNetworkInfo().getTypeName())); - mContext.sendStickyBroadcast(intent); + sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send * out a followup broadcast indicating successful failover @@ -843,7 +846,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); } - mContext.sendStickyBroadcast(intent); + sendStickyBroadcast(intent); } /** @@ -882,7 +885,33 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); info.setFailover(false); } - mContext.sendStickyBroadcast(intent); + sendStickyBroadcast(intent); + } + + private void sendStickyBroadcast(Intent intent) { + synchronized(this) { + if (mSystemReady) { + mContext.sendStickyBroadcast(intent); + } else { + if (mDeferredBroadcasts == null) { + mDeferredBroadcasts = new ArrayList<Intent>(); + } + mDeferredBroadcasts.add(intent); + } + } + } + + void systemReady() { + synchronized(this) { + mSystemReady = true; + if (mDeferredBroadcasts != null) { + int count = mDeferredBroadcasts.size(); + for (int i = 0; i < count; i++) { + mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i)); + } + mDeferredBroadcasts = null; + } + } } private void handleConnect(NetworkInfo info) { diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index fab97b1e1574..f8d0e42f62e1 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -1110,7 +1110,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run synchronized (mLock) { LocationProviderProxy proxy = mProvidersByName.get(provider); - if (provider == null) { + if (proxy == null) { return false; } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 447e9faea7a8..1249289ca27d 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -2054,7 +2054,15 @@ class PowerManagerService extends IPowerManager.Stub if (event.values[0] == 0.0) { goToSleep(milliseconds); } else { - userActivity(milliseconds, false); + // proximity sensor negative events user activity. + // temporarily set mUserActivityAllowed to true so this will work + // even when the keyguard is on. + synchronized (mLocks) { + boolean savedActivityAllowed = mUserActivityAllowed; + mUserActivityAllowed = true; + userActivity(milliseconds, false); + mUserActivityAllowed = savedActivityAllowed; + } } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ad8e8921751d..38bf63affaca 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -85,6 +85,7 @@ class ServerThread extends Thread { HardwareService hardware = null; PowerManagerService power = null; BatteryService battery = null; + ConnectivityService connectivity = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; @@ -231,8 +232,8 @@ class ServerThread extends Thread { try { Log.i(TAG, "Starting Connectivity Service."); - ServiceManager.addService(Context.CONNECTIVITY_SERVICE, - ConnectivityService.getInstance(context)); + connectivity = ConnectivityService.getInstance(context); + ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); } catch (Throwable e) { Log.e(TAG, "Failure starting Connectivity Service", e); } @@ -384,7 +385,8 @@ class ServerThread extends Thread { } if (wallpaper != null) wallpaper.systemReady(); - battery.systemReady(); + if (battery != null) battery.systemReady(); + if (connectivity != null) connectivity.systemReady(); Watchdog.getInstance().start(); Looper.loop(); diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 0a313966859a..9a293a97b89a 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -325,8 +325,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub { ComponentName realName = name; if (realName == null) { // The default component is our static image wallpaper. - realName = new ComponentName("android", - ImageWallpaper.class.getName()); + //realName = new ComponentName("android", + // ImageWallpaper.class.getName()); + clearWallpaperComponentLocked(); + return; } ServiceInfo si = mContext.getPackageManager().getServiceInfo(realName, PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS); diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index a3f1ad840252..fa0ffcd2d2d6 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -94,6 +94,7 @@ public abstract class DataConnectionTracker extends Handler { protected static final int EVENT_PS_RESTRICT_ENABLED = 32; protected static final int EVENT_PS_RESTRICT_DISABLED = 33; public static final int EVENT_CLEAN_UP_CONNECTION = 34; + protected static final int EVENT_CDMA_OTA_PROVISION = 35; //***** Constants @@ -146,6 +147,9 @@ public abstract class DataConnectionTracker extends Handler { protected int mNoRecvPollCount = 0; protected boolean netStatPollEnabled = false; + /** Manage the behavior of data retry after failure */ + protected final RetryManager mRetryMgr = new RetryManager(); + // wifi connection status will be updated by sticky intent protected boolean mIsWifiConnected = false; @@ -202,10 +206,13 @@ public abstract class DataConnectionTracker extends Handler { if (getDataOnRoamingEnabled() != enabled) { Settings.Secure.putInt(phone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); + if (phone.getServiceState().getRoaming()) { + if (enabled) { + mRetryMgr.resetRetryCount(); + } + sendMessage(obtainMessage(EVENT_ROAMING_ON)); + } } - Message roamingMsg = phone.getServiceState().getRoaming() ? - obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); - sendMessage(roamingMsg); } //Retrieve the data roaming setting from the shared preferences. @@ -243,6 +250,9 @@ public abstract class DataConnectionTracker extends Handler { break; case EVENT_ROAMING_OFF: + if (getDataOnRoamingEnabled() == false) { + mRetryMgr.resetRetryCount(); + } onRoamingOff(); break; diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index 46b39a5db6c7..39806e92ef68 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -116,6 +116,7 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_NV_READY = 35; protected static final int EVENT_ERI_FILE_LOADED = 36; protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37; + protected static final int EVENT_SET_RADIO_POWER_OFF = 38; //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index 38bc24d148b5..8bae483215f4 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -48,6 +48,7 @@ import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyEventLog; import java.util.ArrayList; @@ -76,9 +77,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** Currently active CdmaDataConnection */ private CdmaDataConnection mActiveDataConnection; - /** Manage the behavior of data retry after failure */ - private final RetryManager mRetryMgr = new RetryManager(); - /** Defined cdma connection profiles */ private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0; private static final int EXTERNAL_NETWORK_NUM_TYPES = 1; @@ -163,6 +161,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null); p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null); this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); @@ -210,6 +209,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this); mCdmaPhone.mSST.unregisterForRoamingOn(this); mCdmaPhone.mSST.unregisterForRoamingOff(this); + phone.mCM.unregisterForCdmaOtaProvision(this); phone.getContext().unregisterReceiver(this.mIntentReceiver); destroyAllDataConnectionList(); @@ -499,7 +499,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); - cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); + cleanUpConnection(true, Phone.REASON_CDMA_DATA_DETACHED); phone.mCM.setRadioPower(false, null); /* Note: no need to call setRadioPower(true). Assuming the desired * radio power state is still ON (as tracked by ServiceStateTracker), @@ -771,6 +771,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { reason = (String) ar.userObj; } setState(State.IDLE); + + CdmaServiceStateTracker ssTracker = mCdmaPhone.mSST; + ssTracker.processPendingRadioPowerOffAfterDataOff(); + phone.notifyDataConnection(reason); if (retryAfterDisconnected(reason)) { trySetupData(reason); @@ -849,6 +853,22 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } + private void onCdmaOtaProvision(AsyncResult ar) { + if (ar.exception != null) { + int [] otaPrivision = (int [])ar.result; + if ((otaPrivision != null) && (otaPrivision.length > 1)) { + switch (otaPrivision[0]) { + case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED: + case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED: + mRetryMgr.resetRetryCount(); + break; + default: + break; + } + } + } + } + private void writeEventLogCdmaDataDrop() { CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); int bsid = (loc != null) ? loc.getBaseStationId() : -1; @@ -957,6 +977,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { onDataStateChanged((AsyncResult) msg.obj); break; + case EVENT_CDMA_OTA_PROVISION: + onCdmaOtaProvision((AsyncResult) msg.obj); + break; + default: // handle the message in the super class DataConnectionTracker super.handleMessage(msg); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index b42cffd2b18a..b4de09b683f3 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -131,6 +131,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private boolean isEriTextLoaded = false; private boolean isSubscriptionFromRuim = false; + private boolean mPendingRadioPowerOffAfterDataOff = false; + // Registration Denied Reason, General/Authentication Failure, used only for debugging purposes private String mRegistrationDeniedReason; @@ -520,6 +522,16 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; + case EVENT_SET_RADIO_POWER_OFF: + synchronized(this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); + cm.setRadioPower(false, null); + mPendingRadioPowerOffAfterDataOff = false; + } + } + break; + default: Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); break; @@ -548,20 +560,23 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; dcTracker.sendMessage(msg); - // Poll data state up to 50 times, with a 100ms delay - // totaling 5 sec. - // TODO: change the 5 seconds wait from blocking to non-blocking. - for (int i = 0; i < 50; i++) { - DataConnectionTracker.State currentState = dcTracker.getState(); - if (currentState != DataConnectionTracker.State.CONNECTED - && currentState != DataConnectionTracker.State.DISCONNECTING) { - if (DBG) log("Data shutdown complete."); - break; + synchronized(this) { + if (!mPendingRadioPowerOffAfterDataOff) { + DataConnectionTracker.State currentState = dcTracker.getState(); + if (currentState != DataConnectionTracker.State.CONNECTED + && currentState != DataConnectionTracker.State.DISCONNECTING) { + if (DBG) log("Data disconnected, turn off radio right away."); + cm.setRadioPower(false, null); + } + else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 5000)) { + if (DBG) log("Wait 5 sec for data to be disconnected, then turn off radio."); + mPendingRadioPowerOffAfterDataOff = true; + } else { + Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); + cm.setRadioPower(false, null); + } } - SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); } - // If it's on and available and we want it off.. - cm.setRadioPower(false, null); } // Otherwise, we're in the desired state } @@ -1582,4 +1597,22 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { public boolean isMinInfoReady() { return mIsMinInfoReady; } + + /** + * process the pending request to turn radio off after data is disconnected + * + * return true if there is pending request to process; false otherwise. + */ + public boolean processPendingRadioPowerOffAfterDataOff() { + synchronized(this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("Process pending request to turn radio off."); + removeMessages(EVENT_SET_RADIO_POWER_OFF); + cm.setRadioPower(false, null); + mPendingRadioPowerOffAfterDataOff = false; + return true; + } + return false; + } + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index bf60bfe7dff4..34d303965fe3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -96,8 +96,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private int mPdpResetCount = 0; private boolean mIsScreenOn = true; - private final RetryManager mRetryMgr = new RetryManager(); - /** Delay between APN attempts */ protected static final int APN_DELAY_MILLIS = 5000; diff --git a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java index 6b8e1f0bc7bc..1e4f161d9f60 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java @@ -28,7 +28,6 @@ import android.os.Bundle; import java.util.Arrays; import java.util.Comparator; -import java.util.Map; public class AccountManagerServiceTest extends AndroidTestCase { @Override @@ -48,9 +47,9 @@ public class AccountManagerServiceTest extends AndroidTestCase { if (object1 == object2) return 0; if (object1 == null) return 1; if (object2 == null) return -1; - int result = object1.mType.compareTo(object2.mType); + int result = object1.type.compareTo(object2.type); if (result != 0) return result; - return object1.mName.compareTo(object2.mName); + return object1.name.compareTo(object2.name); } } @@ -62,16 +61,14 @@ public class AccountManagerServiceTest extends AndroidTestCase { 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(); + ams.addAccount(a11, "p11", null); + ams.addAccount(a12, "p12", null); + ams.addAccount(a21, "p21", null); + ams.addAccount(a22, "p22", null); + ams.addAccount(a31, "p31", null); + ams.addAccount(a32, "p32", null); + + Account[] accounts = ams.getAccounts(null); Arrays.sort(accounts, new AccountSorter()); assertEquals(6, accounts.length); assertEquals(a11, accounts[0]); @@ -88,7 +85,7 @@ public class AccountManagerServiceTest extends AndroidTestCase { assertEquals(a21, accounts[1]); assertEquals(a31, accounts[2]); - ams.removeAccount(a21); + ams.removeAccount(null, a21); accounts = ams.getAccountsByType("type1" ); Arrays.sort(accounts, new AccountSorter()); @@ -101,8 +98,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { 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.addAccount(a11, "p11", null); + ams.addAccount(a12, "p12", null); assertEquals("p11", ams.getPassword(a11)); assertEquals("p12", ams.getPassword(a12)); @@ -125,8 +122,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { 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)); + ams.addAccount(a11, "p11", u11); + ams.addAccount(a12, "p12", u12); assertEquals("a_a11", ams.getUserData(a11, "a")); assertEquals("b_a11", ams.getUserData(a11, "b")); @@ -149,8 +146,8 @@ public class AccountManagerServiceTest extends AndroidTestCase { 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.addAccount(a11, "p11", null); + ams.addAccount(a12, "p12", null); ams.setAuthToken(a11, "att1", "a11_att1"); ams.setAuthToken(a11, "att2", "a11_att2"); @@ -167,7 +164,7 @@ public class AccountManagerServiceTest extends AndroidTestCase { assertEquals("a12_att3", ams.peekAuthToken(a12, "att3")); ams.setAuthToken(a11, "att3", "a11_att3b"); - ams.invalidateAuthToken(a12.mType, "a12_att2"); + ams.invalidateAuthToken(a12.type, "a12_att2"); assertEquals("a11_att1", ams.peekAuthToken(a11, "att1")); assertEquals("a11_att2", ams.peekAuthToken(a11, "att2")); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java index 97a8b255d3f2..b61b307eb9e2 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java @@ -18,6 +18,7 @@ package com.android.dumprendertree; import android.os.Handler; import android.os.Message; +import android.webkit.MockGeolocation; import android.webkit.WebStorage; import java.util.HashMap; @@ -325,7 +326,7 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon } public void setWindowIsKey(boolean b) { - obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget(); + obtainMessage(LAYOUT_SET_WINDOW_KEY, b ? 1 : 0, 0).sendToTarget(); } public void testRepaint() { @@ -352,4 +353,15 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget(); } + public void setMockGeolocationPosition(double latitude, + double longitude, + double accuracy) { + MockGeolocation.getInstance().setPosition(latitude, + longitude, + accuracy); + } + + public void setMockGeolocationError(int code, String message) { + MockGeolocation.getInstance().setError(code, message); + } } diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java index 42c1e789b9c3..a8af7f83a16d 100644 --- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java +++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java @@ -74,8 +74,8 @@ public class AbstractTableMergerTest extends AndroidTestCase { if (syncVersion != null) values.put("_sync_version", syncVersion); if (syncId != null) values.put("_sync_id", syncId); if (syncAccount != null) { - values.put("_sync_account", syncAccount.mName); - values.put("_sync_account_type", syncAccount.mType); + values.put("_sync_account", syncAccount.name); + values.put("_sync_account_type", syncAccount.type); } values.put("_sync_local_id", syncLocalId); values.put("_sync_dirty", 0); @@ -88,8 +88,8 @@ public class AbstractTableMergerTest extends AndroidTestCase { if (syncVersion != null) values.put("_sync_version", syncVersion); if (syncId != null) values.put("_sync_id", syncId); if (syncAccount != null) { - values.put("_sync_account", syncAccount.mName); - values.put("_sync_account_type", syncAccount.mType); + values.put("_sync_account", syncAccount.name); + values.put("_sync_account_type", syncAccount.type); } if (syncLocalId != null) values.put("_sync_local_id", syncLocalId); return values; diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 57243496f12d..32efa4e9c52d 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -482,6 +482,8 @@ public: const sp<AaptFile>& file, const String8& resType); + void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); } + ssize_t slurpFromArgs(Bundle* bundle); virtual ssize_t slurpFullTree(Bundle* bundle, diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 9d2ed1044b3e..1fa7b18b11ab 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -472,11 +472,22 @@ static bool applyFileOverlay(const sp<AaptAssets>& assets, // didn't find a match fall through and add it.. } baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex)); + assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); } } else { // this group doesn't exist (a file that's only in the overlay) baseSet->add(overlaySet->keyAt(overlayIndex), overlaySet->valueAt(overlayIndex)); + // make sure all flavors are defined in the resources. + sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); + DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles = + overlayGroup->getFiles(); + size_t overlayGroupSize = overlayFiles.size(); + for (size_t overlayGroupIndex = 0; + overlayGroupIndex<overlayGroupSize; + overlayGroupIndex++) { + assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); + } } } // this overlay didn't have resources for this type |