am 13735a2: Merge branch \'readonly-p4-donut\' into donut

Merge commit '13735a255dedd2c2e3b0cff66f0be2e17671f553'

* commit '13735a255dedd2c2e3b0cff66f0be2e17671f553':
  AI 147976: Compatibility mode support. Part 2.
diff --git a/Android.mk b/Android.mk
index de5f5f8..88f023f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -52,7 +52,10 @@
 ##
 ## READ ME: ########################################################
 LOCAL_SRC_FILES += \
-	core/java/android/accounts/IAccountsService.aidl \
+	core/java/android/accounts/IAccountManager.aidl \
+	core/java/android/accounts/IAccountManagerResponse.aidl \
+	core/java/android/accounts/IAccountAuthenticator.aidl \
+	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IActivityWatcher.aidl \
 	core/java/android/app/IAlarmManager.aidl \
@@ -167,7 +170,10 @@
 # relative to the root of the build tree.
 # ============================================================
 aidl_files := \
-	frameworks/base/core/java/android/accounts/IAccountsService.aidl \
+	frameworks/base/core/java/android/accounts/IAccountManager.aidl \
+	frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \
+	frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl \
+	frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
 	frameworks/base/core/java/android/app/Notification.aidl \
 	frameworks/base/core/java/android/app/PendingIntent.aidl \
 	frameworks/base/core/java/android/content/ComponentName.aidl \
diff --git a/api/current.xml b/api/current.xml
index 1bf1d5a9..1a863f0 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1571,6 +1571,17 @@
  visibility="public"
 >
 </field>
+<field name="accountType"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843372"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="action"
  type="int"
  transient="false"
@@ -12557,6 +12568,2208 @@
 </constructor>
 </class>
 </package>
+<package name="android.accounts"
+>
+<class name="AbstractAccountAuthenticator"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AbstractAccountAuthenticator"
+ type="android.accounts.AbstractAccountAuthenticator"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addAccount"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+</method>
+<method name="confirmPassword"
+ return="boolean"
+ abstract="true"
+ 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>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="editProperties"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="getIAccountAuthenticator"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasFeatures"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="updateCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Account"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountAuthenticatorActivity"
+ extends="android.app.Activity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AccountAuthenticatorActivity"
+ type="android.accounts.AccountAuthenticatorActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="setAccountAuthenticatorResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="AccountAuthenticatorCache"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AccountAuthenticatorCache"
+ type="android.accounts.AccountAuthenticatorCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="fout" type="java.io.PrintWriter">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="getAllAuthenticators"
+ return="java.util.Collection&lt;android.accounts.AccountAuthenticatorCache.AuthenticatorInfo&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAuthenticatorInfo"
+ return="android.accounts.AccountAuthenticatorCache.AuthenticatorInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</method>
+<method name="parseAuthenticatorInfo"
+ return="android.accounts.AccountAuthenticatorCache.AuthenticatorInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="android.content.pm.ResolveInfo">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="XmlPullParserException" type="org.xmlpull.v1.XmlPullParserException">
+</exception>
+</method>
+</class>
+<class name="AccountAuthenticatorCache.AuthenticatorInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="mComponentName"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountAuthenticatorResponse"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+</constructor>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="addAccount"
+ return="android.accounts.Future2"
+ 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="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="addAccountExplicitly"
+ return="android.accounts.Future1&lt;java.lang.Boolean&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Boolean&gt;">
+</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"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<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"
+ 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="notifyAuthFailure" type="boolean">
+</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="blockingGetAuthenticatorTypes"
+ return="java.lang.String[]"
+ 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&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</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"
+ 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="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="confirmPassword"
+ return="android.accounts.Future1&lt;java.lang.Boolean&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Boolean&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="editProperties"
+ return="android.accounts.Future2"
+ 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="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="get"
+ return="android.accounts.AccountManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getAccounts"
+ return="android.accounts.Future1&lt;android.accounts.Account[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;android.accounts.Account[]&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAccountsByType"
+ return="android.accounts.Future1&lt;android.accounts.Account[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;android.accounts.Account[]&gt;">
+</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"
+ 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>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.Future2"
+ 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="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.Future2"
+ 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="notifyAuthFailure" type="boolean">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthTokenByFeatures"
+ 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="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<parameter name="activityForPrompting" type="android.app.Activity">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthenticatorTypes"
+ return="android.accounts.Future1&lt;java.lang.String[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String[]&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getPassword"
+ return="android.accounts.Future1&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</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&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</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&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</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&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</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&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="removeOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+</method>
+<method name="setAuthToken"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</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&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</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&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</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"
+ 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="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+</class>
+<class name="AuthenticatorBindHelper"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AuthenticatorBindHelper"
+ type="android.accounts.AuthenticatorBindHelper"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="authenticatorCache" type="android.accounts.AccountAuthenticatorCache">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<parameter name="messageWhatConnected" type="int">
+</parameter>
+<parameter name="messageWhatDisconnected" type="int">
+</parameter>
+</constructor>
+<method name="bind"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authenticatorType" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.accounts.AuthenticatorBindHelper.Callback">
+</parameter>
+</method>
+<method name="unbind"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callbackToUnbind" type="android.accounts.AuthenticatorBindHelper.Callback">
+</parameter>
+</method>
+</class>
+<interface name="AuthenticatorBindHelper.Callback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onConnected"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onDisconnected"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
+<class name="AuthenticatorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="ChooseAccountActivity"
+ extends="android.app.ListActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ChooseAccountActivity"
+ type="android.accounts.ChooseAccountActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Constants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="ACCOUNTS_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accounts&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_AUTHENTICATOR_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountAuthenticatorResponse&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_MANAGER_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountManagerResponse&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_NAME_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authAccount&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_TYPE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountType&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_TYPES_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authenticator_types&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHTOKEN_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authtoken&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTH_FAILED_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authFailedMessage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOOLEAN_RESULT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;booleanResult&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_BAD_ARGUMENTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_INVALID_RESPONSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;errorCode&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_NETWORK_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_REMOTE_EXCEPTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_UNSUPPORTED_OPERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;errorMessage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INTENT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;intent&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOGIN_ACCOUNTS_CHANGED_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.accounts.LOGIN_ACCOUNTS_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;password&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USERDATA_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;userdata&quot;"
+ 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&lt;V&gt;">
+</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"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="future" type="android.accounts.Future2">
+</parameter>
+</method>
+</interface>
+<interface name="IAccountAuthenticator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="addAccount"
+ 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="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ 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="confirmPassword"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="editProperties"
+ 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="accountType" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="getAuthToken"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="hasFeatures"
+ 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>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="updateCredentials"
+ 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>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticator.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticator">
+</implements>
+<constructor name="IAccountAuthenticator.Stub"
+ type="android.accounts.IAccountAuthenticator.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<interface name="IAccountAuthenticatorResponse"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticatorResponse.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticatorResponse">
+</implements>
+<constructor name="IAccountAuthenticatorResponse.Stub"
+ type="android.accounts.IAccountAuthenticatorResponse.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticatorResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<class name="NetworkErrorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<interface name="OnAccountsUpdatedListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onAccountsUpdated"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accounts" type="android.accounts.Account[]">
+</parameter>
+</method>
+</interface>
+<class name="OperationCanceledException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+</package>
 <package name="android.app"
 >
 <class name="Activity"
@@ -24860,6 +27073,17 @@
 <parameter name="receiver" type="android.content.BroadcastReceiver">
 </parameter>
 </method>
+<field name="ACCOUNT_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTIVITY_SERVICE"
  type="java.lang.String"
  transient="false"
@@ -28383,7 +30607,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.intent.action.ACTION_POWER_CONNECTED&quot;"
+ value="&quot;android.intent.action.POWER_CONNECTED&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -28394,7 +30618,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.intent.action.ACTION_POWER_DISCONNECTED&quot;"
+ value="&quot;android.intent.action.POWER_DISCONNECTED&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -96813,6 +99037,17 @@
  visibility="public"
 >
 </field>
+<field name="GROUP_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;group_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="GROUP_SYNC_ID"
  type="java.lang.String"
  transient="false"
@@ -98755,6 +100990,17 @@
  visibility="public"
 >
 </field>
+<field name="_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </interface>
 <class name="LiveFolders"
  extends="java.lang.Object"
@@ -102663,6 +104909,17 @@
  visibility="public"
 >
 </field>
+<field name="ALARM_ALERT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;alarm_alert&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ALWAYS_FINISH_ACTIVITIES"
  type="java.lang.String"
  transient="false"
@@ -102783,6 +105040,16 @@
  visibility="public"
 >
 </field>
+<field name="DEFAULT_ALARM_ALERT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DEFAULT_NOTIFICATION_URI"
  type="android.net.Uri"
  transient="false"
@@ -151899,7 +154166,7 @@
  synchronized="true"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -152333,7 +154600,7 @@
  synchronized="true"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="use" type="boolean">
@@ -156658,6 +158925,39 @@
  visibility="public"
 >
 </method>
+<method name="getDropDownBackground"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownHorizontalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownVerticalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDropDownWidth"
  return="int"
  abstract="false"
@@ -156881,6 +159181,58 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
+<method name="setDropDownBackgroundDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setDropDownBackgroundResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="setDropDownHorizontalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setDropDownVerticalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
 <method name="setDropDownWidth"
  return="void"
  abstract="false"
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
new file mode 100644
index 0000000..474755c
--- /dev/null
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -0,0 +1,196 @@
+/*
+ * 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 android.os.RemoteException;
+
+/**
+ * Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator
+ * binder interface and also provides helper libraries to simplify the creation of
+ * AccountAuthenticators.
+ */
+public abstract class AbstractAccountAuthenticator {
+    class Transport extends IAccountAuthenticator.Stub {
+        public void addAccount(IAccountAuthenticatorResponse response, String accountType,
+                String authTokenType, String[] requiredFeatures, Bundle options)
+                throws RemoteException {
+            final Bundle result;
+            try {
+                result = AbstractAccountAuthenticator.this.addAccount(
+                    new AccountAuthenticatorResponse(response),
+                        accountType, authTokenType, requiredFeatures, options);
+            } catch (NetworkErrorException e) {
+                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+                return;
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "addAccount not supported");
+                return;
+            }
+            if (result != null) {
+                response.onResult(result);
+            }
+        }
+
+        public void confirmPassword(IAccountAuthenticatorResponse response,
+                Account account, String password) throws RemoteException {
+            boolean result;
+            try {
+                result = AbstractAccountAuthenticator.this.confirmPassword(
+                    new AccountAuthenticatorResponse(response),
+                        account, password);
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "confirmPassword not supported");
+                return;
+            } catch (NetworkErrorException e) {
+                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+                return;
+            }
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result);
+            response.onResult(bundle);
+        }
+
+        public void confirmCredentials(IAccountAuthenticatorResponse response,
+                Account account) throws RemoteException {
+            final Bundle result;
+            try {
+                result = AbstractAccountAuthenticator.this.confirmCredentials(
+                    new AccountAuthenticatorResponse(response), account);
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "confirmCredentials not supported");
+                return;
+            }
+            if (result != null) {
+                response.onResult(result);
+            }
+        }
+
+        public void getAuthToken(IAccountAuthenticatorResponse response,
+                Account account, String authTokenType, Bundle loginOptions)
+                throws RemoteException {
+            try {
+                final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
+                        new AccountAuthenticatorResponse(response), account,
+                        authTokenType, loginOptions);
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "getAuthToken not supported");
+            } catch (NetworkErrorException e) {
+                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+            }
+        }
+
+        public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
+                String authTokenType, Bundle loginOptions) throws RemoteException {
+            final Bundle result;
+            try {
+                result = AbstractAccountAuthenticator.this.updateCredentials(
+                    new AccountAuthenticatorResponse(response), account,
+                        authTokenType, loginOptions);
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "updateCredentials not supported");
+                return;
+            }
+            if (result != null) {
+                response.onResult(result);
+            }
+        }
+
+        public void editProperties(IAccountAuthenticatorResponse response,
+                String accountType) throws RemoteException {
+            final Bundle result;
+            try {
+                result = AbstractAccountAuthenticator.this.editProperties(
+                    new AccountAuthenticatorResponse(response), accountType);
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "editProperties not supported");
+                return;
+            }
+            if (result != null) {
+                response.onResult(result);
+            }
+        }
+
+        public void hasFeatures(IAccountAuthenticatorResponse response,
+                Account account, String[] features) throws RemoteException {
+            final Bundle result;
+            try {
+                result = AbstractAccountAuthenticator.this.hasFeatures(
+                    new AccountAuthenticatorResponse(response), account, features);
+            } catch (UnsupportedOperationException e) {
+                response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+                        "hasFeatures not supported");
+                return;
+            } catch (NetworkErrorException e) {
+                response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+                return;
+            }
+            if (result != null) {
+                response.onResult(result);
+            }
+        }
+    }
+
+    Transport mTransport = new Transport();
+
+    /**
+     * @return the IAccountAuthenticator binder transport object
+     */
+    public final IAccountAuthenticator getIAccountAuthenticator()
+    {
+        return mTransport;
+    }
+
+    /**
+     * Returns a Bundle that contains the Intent of the activity that can be used to edit the
+     * properties. In order to indicate success the activity should call response.setResult()
+     * with a non-null Bundle.
+     * @param response used to set the result for the request. If the Constants.INTENT_KEY
+     *   is set in the bundle then this response field is to be used for sending future
+     *   results if and when the Intent is started.
+     * @param accountType the AccountType whose properties are to be edited.
+     * @return a Bundle containing the result or the Intent to start to continue the request.
+     *   If this is null then the request is considered to still be active and the result should
+     *   sent later using response.
+     */
+    public abstract Bundle editProperties(AccountAuthenticatorResponse response,
+            String accountType);
+    public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException;
+    /* @deprecated */
+    public abstract boolean confirmPassword(AccountAuthenticatorResponse response,
+            Account account, String password) throws NetworkErrorException;
+    public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
+            Account account);
+    public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
+            Account account, String authTokenType, Bundle loginOptions)
+            throws NetworkErrorException;
+    public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
+            Account account, String authTokenType, Bundle loginOptions);
+    public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
+            Account account, String[] features) throws NetworkErrorException;
+}
diff --git a/core/java/android/accounts/Account.aidl b/core/java/android/accounts/Account.aidl
new file mode 100644
index 0000000..8752d99
--- /dev/null
+++ b/core/java/android/accounts/Account.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+parcelable Account;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
new file mode 100644
index 0000000..30c91b0
--- /dev/null
+++ b/core/java/android/accounts/Account.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+
+/**
+ * Value type that represents an Account in the {@link AccountManager}. This object is
+ * {@link Parcelable} and also overrides {@link #equals} and {@link #hashCode}, making it
+ * suitable for use as the key of a {@link java.util.Map}
+ */
+public class Account implements Parcelable {
+    public final String mName;
+    public final String mType;
+
+    public boolean equals(Object o) {
+        if (o == this) return true;
+        if (!(o instanceof Account)) return false;
+        final Account other = (Account)o;
+        return mName.equals(other.mName) && mType.equals(other.mType);
+    }
+
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + mName.hashCode();
+        result = 31 * result + mType.hashCode();
+        return result;
+    }
+
+    public Account(String name, String type) {
+        if (TextUtils.isEmpty(name)) {
+            throw new IllegalArgumentException("the name must not be empty: " + name);
+        }
+        if (TextUtils.isEmpty(type)) {
+            throw new IllegalArgumentException("the type must not be empty: " + type);
+        }
+        mName = name;
+        mType = type;
+    }
+
+    public Account(Parcel in) {
+        mName = in.readString();
+        mType = in.readString();
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mName);
+        dest.writeString(mType);
+    }
+
+    public static final Creator<Account> CREATOR = new Creator<Account>() {
+        public Account createFromParcel(Parcel source) {
+            return new Account(source);
+        }
+
+        public Account[] newArray(int size) {
+            return new Account[size];
+        }
+    };
+
+    public String toString() {
+        return "Account {name=" + mName + ", type=" + mType + "}";
+    }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
new file mode 100644
index 0000000..0319ab9
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Base class for implementing an Activity that is used to help implement an
+ * AbstractAccountAuthenticator. If the AbstractAccountAuthenticator needs to return an Intent
+ * that is to be used to launch an Activity that needs to return results to satisfy an
+ * AbstractAccountAuthenticator request, it should store the AccountAuthenticatorResponse
+ * inside of the Intent as follows:
+ * <p>
+ *      intent.putExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY, response);
+ * <p>
+ * The activity that it launches should extend the AccountAuthenticatorActivity. If this
+ * activity has a result that satisfies the original request it sets it via:
+ * <p>
+ *       setAccountAuthenticatorResult(result)
+ * <p>
+ * This result will be sent as the result of the request when the activity finishes. If this
+ * is never set or if it is set to null then the request will be canceled when the activity
+ * finishes.
+ */
+public class AccountAuthenticatorActivity extends Activity {
+    private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
+    private Bundle mResultBundle = null;
+
+    /**
+     * Set the result that is to be sent as the result of the request that caused this
+     * Activity to be launched. If result is null or this method is never called then
+     * the request will be canceled.
+     * @param result this is returned as the result of the AbstractAccountAuthenticator request
+     */
+    public final void setAccountAuthenticatorResult(Bundle result) {
+        mResultBundle = result;
+    }
+
+    /**
+     * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
+     * icicle is non-zero.
+     * @param icicle the save instance data of this Activity, may be null
+     */
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        if (icicle == null) {
+            Intent intent = getIntent();
+            mAccountAuthenticatorResponse =
+                    intent.getParcelableExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+        } else {
+            mAccountAuthenticatorResponse =
+                    icicle.getParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+        }
+
+        if (mAccountAuthenticatorResponse != null) {
+            mAccountAuthenticatorResponse.onRequestContinued();
+        }
+    }
+
+    /**
+     * Saves the AccountAuthenticatorResponse in the instance state.
+     * @param outState where to store any instance data
+     */
+    protected void onSaveInstanceState(Bundle outState) {
+        outState.putParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY,
+                mAccountAuthenticatorResponse);
+        super.onSaveInstanceState(outState);
+    }
+
+    /**
+     * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
+     */
+    public void finish() {
+        if (mAccountAuthenticatorResponse != null) {
+            // send the result bundle back if set, otherwise send an error.
+            if (mResultBundle != null) {
+                mAccountAuthenticatorResponse.onResult(mResultBundle);
+            } else {
+                mAccountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+            }
+            mAccountAuthenticatorResponse = null;
+        }
+        super.finish();
+    }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
new file mode 100644
index 0000000..6a14ff8
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.XmlResourceParser;
+import android.content.res.TypedArray;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A cache of services that export the {@link IAccountAuthenticator} interface. This cache
+ * is built by interrogating the {@link PackageManager} and is updated as packages are added,
+ * removed and changed. The authenticators are referred to by their account type and
+ * are made available via the {@link #getAuthenticatorInfo(String type)} method.
+ */
+public class AccountAuthenticatorCache {
+    private static final String TAG = "Account";
+
+    private static final String SERVICE_INTERFACE = "android.accounts.AccountAuthenticator";
+    private static final String SERVICE_META_DATA = "android.accounts.AccountAuthenticator";
+
+    private volatile Map<String, AuthenticatorInfo> mAuthenticators;
+
+    private final Context mContext;
+    private BroadcastReceiver mReceiver;
+
+    public AccountAuthenticatorCache(Context context) {
+        mContext = context;
+        mReceiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                buildAuthenticatorList();
+            }
+        };
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        getAllAuthenticators();
+        Map<String, AuthenticatorInfo> authenticators = mAuthenticators;
+        fout.println("AccountAuthenticatorCache: " + authenticators.size() + " authenticators");
+        for (AuthenticatorInfo info : authenticators.values()) {
+            fout.println("  " + info);
+        }
+    }
+
+    private void monitorPackageChanges() {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        mContext.registerReceiver(mReceiver, intentFilter);
+    }
+
+    /**
+     * Value type that describes an AccountAuthenticator. The information within can be used
+     * to bind to its {@link IAccountAuthenticator} interface.
+     */
+    public class AuthenticatorInfo {
+        public final String mType;
+        public final ComponentName mComponentName;
+
+        private AuthenticatorInfo(String type, ComponentName componentName) {
+            mType = type;
+            mComponentName = componentName;
+        }
+
+        public String toString() {
+            return "AuthenticatorInfo: " + mType + ", " + mComponentName;
+        }
+    }
+
+    /**
+     * Accessor for the registered authenticators.
+     * @param type the account type of the authenticator
+     * @return the AuthenticatorInfo that matches the account type or null if none is present
+     */
+    public AuthenticatorInfo getAuthenticatorInfo(String type) {
+        if (mAuthenticators == null) {
+            monitorPackageChanges();
+            buildAuthenticatorList();
+        }
+        return mAuthenticators.get(type);
+    }
+
+    /**
+     * @return a collection of {@link AuthenticatorInfo} objects for all
+     * registered authenticators.
+     */
+    public Collection<AuthenticatorInfo> getAllAuthenticators() {
+        if (mAuthenticators == null) {
+            monitorPackageChanges();
+            buildAuthenticatorList();
+        }
+        return Collections.unmodifiableCollection(mAuthenticators.values());
+    }
+
+    /**
+     * Stops the monitoring of package additions, removals and changes.
+     */
+    public void close() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        if (mReceiver != null) {
+            Log.e(TAG, "AccountAuthenticatorCache finalized without being closed");
+        }
+        close();
+        super.finalize();
+    }
+
+    private void buildAuthenticatorList() {
+        Map<String, AuthenticatorInfo> authenticators = Maps.newHashMap();
+        PackageManager pm = mContext.getPackageManager();
+
+        List<ResolveInfo> services =
+                pm.queryIntentServices(new Intent(SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+
+        for (ResolveInfo resolveInfo : services) {
+            try {
+                AuthenticatorInfo info = parseAuthenticatorInfo(resolveInfo);
+                if (info != null) {
+                    authenticators.put(info.mType, info);
+                } else {
+                    Log.w(TAG, "Unable to load input method " + resolveInfo.toString());
+                }
+            } catch (XmlPullParserException e) {
+                Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+            } catch (IOException e) {
+                Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+            }
+        }
+
+        mAuthenticators = authenticators;
+    }
+
+    public AuthenticatorInfo parseAuthenticatorInfo(ResolveInfo service)
+            throws XmlPullParserException, IOException {
+        ServiceInfo si = service.serviceInfo;
+        ComponentName componentName = new ComponentName(si.packageName, si.name);
+
+        PackageManager pm = mContext.getPackageManager();
+        String authenticatorType = null;
+
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, SERVICE_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No " + SERVICE_META_DATA + " meta-data");
+            }
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+
+            String nodeName = parser.getName();
+            if (!"account-authenticator".equals(nodeName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with account-authenticator tag");
+            }
+
+            TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+                    com.android.internal.R.styleable.AccountAuthenticator);
+            authenticatorType = sa.getString(
+                    com.android.internal.R.styleable.AccountAuthenticator_accountType);
+            sa.recycle();
+        } finally {
+            if (parser != null) parser.close();
+        }
+
+        if (authenticatorType == null) {
+            return null;
+        }
+
+        return new AuthenticatorInfo(authenticatorType, componentName);
+    }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
new file mode 100644
index 0000000..7198046
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.java
@@ -0,0 +1,82 @@
+/*
+ * 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 android.os.Parcelable;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link IAccountAuthenticatorResponse} object.
+ * TODO: this interface is still in flux
+ */
+public class AccountAuthenticatorResponse implements Parcelable {
+    private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
+
+    public AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
+        mAccountAuthenticatorResponse = response;
+    }
+
+    public AccountAuthenticatorResponse(Parcel parcel) {
+        mAccountAuthenticatorResponse =
+                IAccountAuthenticatorResponse.Stub.asInterface(parcel.readStrongBinder());
+    }
+
+    public void onResult(Bundle result) {
+        try {
+            mAccountAuthenticatorResponse.onResult(result);
+        } catch (RemoteException e) {
+            // this should never happen
+        }
+    }
+
+    public void onRequestContinued() {
+        try {
+            mAccountAuthenticatorResponse.onRequestContinued();
+        } catch (RemoteException e) {
+            // this should never happen
+        }
+    }
+
+    public void onError(int errorCode, String errorMessage) {
+        try {
+            mAccountAuthenticatorResponse.onError(errorCode, errorMessage);
+        } catch (RemoteException e) {
+            // this should never happen
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mAccountAuthenticatorResponse.asBinder());
+    }
+
+    public static final Creator<AccountAuthenticatorResponse> CREATOR =
+            new Creator<AccountAuthenticatorResponse>() {
+        public AccountAuthenticatorResponse createFromParcel(Parcel source) {
+            return new AccountAuthenticatorResponse(source);
+        }
+
+        public AccountAuthenticatorResponse[] newArray(int size) {
+            return new AccountAuthenticatorResponse[size];
+        }
+    };
+}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
new file mode 100644
index 0000000..4fcaa88
--- /dev/null
+++ b/core/java/android/accounts/AccountManager.java
@@ -0,0 +1,1073 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.os.Bundle;
+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;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+
+/**
+ * A class that helps with interactions with the AccountManagerService. It provides
+ * methods to allow for account, password, and authtoken management for all accounts on the
+ * device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. One accesses the {@link AccountManager} by calling:
+ *    AccountManager accountManager = AccountManager.get(context);
+ *
+ * <p>
+ * TODO(fredq) this interface is still in flux
+ */
+public class AccountManager {
+    private static final String TAG = "AccountManager";
+
+    private final Context mContext;
+    private final IAccountManager mService;
+    private final Handler mMainHandler;
+
+    /**
+     * @hide
+     */
+    public AccountManager(Context context, IAccountManager service) {
+        mContext = context;
+        mService = service;
+        mMainHandler = new Handler(mContext.getMainLooper());
+    }
+
+    /**
+     * @hide used for testing only
+     */
+    public AccountManager(Context context, IAccountManager service, Handler handler) {
+        mContext = context;
+        mService = service;
+        mMainHandler = handler;
+    }
+
+    public static AccountManager get(Context context) {
+        return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+    }
+
+    public String blockingGetPassword(Account account) {
+        ensureNotOnMainThread();
+        try {
+            return mService.getPassword(account);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            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();
+        try {
+            return mService.getUserData(account, key);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            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 String[] blockingGetAuthenticatorTypes() {
+        ensureNotOnMainThread();
+        try {
+            return mService.getAuthenticatorTypes();
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Future1<String[]> getAuthenticatorTypes(Future1Callback<String[]> callback,
+            Handler handler) {
+        return startAsFuture(callback, handler, new Callable<String[]>() {
+            public String[] call() throws Exception {
+                return blockingGetAuthenticatorTypes();
+            }
+        });
+    }
+
+    public Account[] blockingGetAccounts() {
+        ensureNotOnMainThread();
+        try {
+            return mService.getAccounts();
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Account[] blockingGetAccountsByType(String accountType) {
+        ensureNotOnMainThread();
+        try {
+            return mService.getAccountsByType(accountType);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            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();
+        try {
+            return mService.addAccount(account, password, extras);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            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 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 void blockingInvalidateAuthToken(String accountType, String authToken) {
+        ensureNotOnMainThread();
+        try {
+            mService.invalidateAuthToken(accountType, authToken);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+        }
+    }
+
+    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();
+        try {
+            return mService.peekAuthToken(account, authTokenType);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+            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();
+        try {
+            mService.setPassword(account, password);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+        }
+    }
+
+    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();
+        try {
+            mService.clearPassword(account);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+        }
+    }
+
+    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();
+        try {
+            mService.setUserData(account, key, value);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+        }
+    }
+
+    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();
+        try {
+            mService.setAuthToken(account, authTokenType, authToken);
+        } catch (RemoteException e) {
+            // if this happens the entire runtime will restart
+        }
+    }
+
+    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);
+    }
+
+    /**
+     * Request the auth token for this account/authTokenType. If this succeeds then the
+     * auth token will then be passed to the activity. If this results in an authentication
+     * failure then a login intent will be returned that can be invoked to prompt the user to
+     * update their credentials. This login activity will return the auth token to the calling
+     * activity. If activity is null then the login intent will not be invoked.
+     *
+     * @param account the account whose auth token should be retrieved
+     * @param authTokenType the auth token type that should be retrieved
+     * @param loginOptions
+     * @param activity the activity to launch the login intent, if necessary, and to which
+     */
+    public Future2 getAuthToken(
+            final Account account, final String authTokenType, final Bundle loginOptions,
+            final Activity activity, Future2Callback 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) {
+            public void doWork() throws RemoteException {
+                mService.getAuthToken(mResponse, account, authTokenType,
+                        false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
+                        loginOptions);
+            }
+        }.start();
+    }
+
+    public Future2 getAuthToken(
+            final Account account, final String authTokenType, final boolean notifyAuthFailure,
+            Future2Callback 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) {
+            public void doWork() throws RemoteException {
+                mService.getAuthToken(mResponse, account, authTokenType,
+                        notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
+            }
+        }.start();
+    }
+
+    public Future2 addAccount(final String accountType,
+            final String authTokenType, final String[] requiredFeatures,
+            final Bundle addAccountOptions,
+            final Activity activity, Future2Callback callback, Handler handler) {
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.addAcount(mResponse, accountType, authTokenType,
+                        requiredFeatures, activity != null, addAccountOptions);
+            }
+        }.start();
+    }
+
+    /** @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 void doWork() throws RemoteException {
+                mService.confirmPassword(response, 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 Future2 getAccountsWithTypeAndFeatures(
+            final String type, final String[] features,
+            Future2Callback callback, Handler handler) {
+        if (type == null) throw new IllegalArgumentException("type is null");
+        return new AmsTask(null /* activity */, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.getAccountsByTypeAndFeatures(mResponse, type, features);
+            }
+        }.start();
+    }
+
+    public Future2 confirmCredentials(final Account account, final Activity activity,
+            final Future2Callback callback,
+            final Handler handler) {
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.confirmCredentials(mResponse, account, activity != null);
+            }
+        }.start();
+    }
+
+    public Future2 updateCredentials(final Account account, final String authTokenType,
+            final Bundle loginOptions, final Activity activity,
+            final Future2Callback callback,
+            final Handler handler) {
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.updateCredentials(mResponse, account, authTokenType, activity != null,
+                        loginOptions);
+            }
+        }.start();
+    }
+
+    public Future2 editProperties(final String accountType, final Activity activity,
+            final Future2Callback callback,
+            final Handler handler) {
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.editProperties(mResponse, accountType, activity != null);
+            }
+        }.start();
+    }
+
+    private void ensureNotOnMainThread() {
+        final Looper looper = Looper.myLooper();
+        if (looper != null && looper == mContext.getMainLooper()) {
+            // We really want to throw an exception here, but GTalkService exercises this
+            // path quite a bit and needs some serious rewrite in order to work properly.
+            //noinspection ThrowableInstanceNeverThrow
+//            Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
+//                    new Exception());
+            // TODO(fredq) remove the log and throw this exception when the callers are fixed
+//            throw new IllegalStateException(
+//                    "calling this from your main thread can lead to deadlock");
+        }
+    }
+
+    private void postToHandler(Handler handler, final Future2Callback callback,
+            final Future2 future) {
+        handler = handler == null ? mMainHandler : handler;
+        handler.post(new Runnable() {
+            public void run() {
+                callback.run(future);
+            }
+        });
+    }
+
+    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;
+        handler.post(new Runnable() {
+            public void run() {
+                callback.run(future);
+            }
+        });
+    }
+
+    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 {
+        final IAccountManagerResponse mResponse;
+        final Handler mHandler;
+        final Future2Callback mCallback;
+        final Activity mActivity;
+        final Thread mThread;
+        public AmsTask(Activity activity, Handler handler, Future2Callback callback) {
+            super(new Callable<Bundle>() {
+                public Bundle call() throws Exception {
+                    throw new IllegalStateException("this should never be called");
+                }
+            });
+
+            mHandler = handler;
+            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();
+            return this;
+        }
+
+        public abstract void doWork() throws RemoteException;
+
+        private Bundle internalGetResult(Long timeout, TimeUnit unit)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            try {
+                if (timeout == null) {
+                    return get();
+                } else {
+                    return get(timeout, unit);
+                }
+            } catch (CancellationException e) {
+                throw new OperationCanceledException();
+            } catch (TimeoutException e) {
+                // fall through and cancel
+            } catch (InterruptedException e) {
+                // fall through and cancel
+            } catch (ExecutionException e) {
+                final Throwable cause = e.getCause();
+                if (cause instanceof IOException) {
+                    throw (IOException) cause;
+                } else if (cause instanceof UnsupportedOperationException) {
+                    throw new AuthenticatorException(cause);
+                } else if (cause instanceof AuthenticatorException) {
+                    throw (AuthenticatorException) cause;
+                } else if (cause instanceof RuntimeException) {
+                    throw (RuntimeException) cause;
+                } else if (cause instanceof Error) {
+                    throw (Error) cause;
+                } else {
+                    throw new IllegalStateException(cause);
+                }
+            } finally {
+                cancel(true /* interrupt if running */);
+            }
+            throw new OperationCanceledException();
+        }
+
+        public Bundle getResult()
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return internalGetResult(null, null);
+        }
+
+        public Bundle getResult(long timeout, TimeUnit unit)
+                throws OperationCanceledException, IOException, AuthenticatorException {
+            return internalGetResult(timeout, unit);
+        }
+
+        protected void done() {
+            if (mCallback != null) {
+                postToHandler(mHandler, mCallback, this);
+            }
+        }
+
+        /** Handles the responses from the AccountManager */
+        private class Response extends IAccountManagerResponse.Stub {
+            public void onResult(Bundle bundle) {
+                Intent intent = bundle.getParcelable("intent");
+                if (intent != null && mActivity != null) {
+                    // since the user provided an Activity we will silently start intents
+                    // that we see
+                    mActivity.startActivity(intent);
+                    // leave the Future running to wait for the real response to this request
+                } else {
+                    set(bundle);
+                }
+            }
+
+            public void onError(int code, String message) {
+                if (code == Constants.ERROR_CODE_CANCELED) {
+                    // the authenticator indicated that this request was canceled, do so now
+                    cancel(true /* mayInterruptIfRunning */);
+                    return;
+                }
+                setException(convertErrorToException(code, message));
+            }
+        }
+
+    }
+
+    private abstract class AMSTaskBoolean extends FutureTask<Boolean> implements Future1<Boolean> {
+        final IAccountManagerResponse response;
+        final Handler mHandler;
+        final Future1Callback<Boolean> mCallback;
+        public AMSTaskBoolean(Handler handler, Future1Callback<Boolean> callback) {
+            super(new Callable<Boolean>() {
+                public Boolean call() throws Exception {
+                    throw new IllegalStateException("this should never be called");
+                }
+            });
+
+            mHandler = handler;
+            mCallback = callback;
+            response = new Response();
+
+            new Thread(new Runnable() {
+                public void run() {
+                    try {
+                        doWork();
+                    } catch (RemoteException e) {
+                        // never happens
+                    }
+                }
+            }).start();
+        }
+
+        public abstract void doWork() throws RemoteException;
+
+
+        protected void done() {
+            if (mCallback != null) {
+                postToHandler(mHandler, mCallback, this);
+            }
+        }
+
+        private Boolean internalGetResult(Long timeout, TimeUnit unit) {
+            try {
+                if (timeout == null) {
+                    return get();
+                } else {
+                    return get(timeout, unit);
+                }
+            } catch (InterruptedException e) {
+                // fall through and cancel
+            } catch (TimeoutException e) {
+                // fall through and cancel
+            } catch (CancellationException e) {
+                return false;
+            } catch (ExecutionException e) {
+                final Throwable cause = e.getCause();
+                if (cause instanceof IOException) {
+                    return false;
+                } else if (cause instanceof UnsupportedOperationException) {
+                    return false;
+                } else if (cause instanceof AuthenticatorException) {
+                    return false;
+                } else if (cause instanceof RuntimeException) {
+                    throw (RuntimeException) cause;
+                } else if (cause instanceof Error) {
+                    throw (Error) cause;
+                } else {
+                    throw new IllegalStateException(cause);
+                }
+            } finally {
+                cancel(true /* interrupt if running */);
+            }
+            return false;
+        }
+
+        public Boolean getResult() throws OperationCanceledException {
+            return internalGetResult(null, null);
+        }
+
+        public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
+            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) {
+        if (code == Constants.ERROR_CODE_NETWORK_ERROR) {
+            return new IOException(message);
+        }
+
+        if (code == Constants.ERROR_CODE_UNSUPPORTED_OPERATION) {
+            return new UnsupportedOperationException(message);
+        }
+
+        if (code == Constants.ERROR_CODE_INVALID_RESPONSE) {
+            return new AuthenticatorException(message);
+        }
+
+        if (code == Constants.ERROR_CODE_BAD_ARGUMENTS) {
+            return new IllegalArgumentException(message);
+        }
+
+        return new AuthenticatorException(message);
+    }
+
+    private class GetAuthTokenByTypeAndFeaturesTask extends AmsTask implements Future2Callback {
+        GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
+                final String[] features, Activity activityForPrompting,
+                final Bundle addAccountOptions, final Bundle loginOptions,
+                Future2Callback callback, Handler handler) {
+            super(activityForPrompting, handler, callback);
+            if (accountType == null) throw new IllegalArgumentException("account type is null");
+            mAccountType = accountType;
+            mAuthTokenType = authTokenType;
+            mFeatures = features;
+            mAddAccountOptions = addAccountOptions;
+            mLoginOptions = loginOptions;
+            mMyCallback = this;
+        }
+        volatile Future2 mFuture = null;
+        final String mAccountType;
+        final String mAuthTokenType;
+        final String[] mFeatures;
+        final Bundle mAddAccountOptions;
+        final Bundle mLoginOptions;
+        final Future2Callback 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);
+                            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((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,
+                                            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
+                        }
+                    }
+                }}, mHandler);
+        }
+
+
+
+        // TODO(fredq) pass through the calls to our implemention of Future2 to the underlying
+        // future that we create. We need to do things like have cancel cancel the mFuture, if set
+        // 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) {
+            try {
+                set(future.get());
+            } catch (InterruptedException e) {
+                cancel(true);
+            } catch (CancellationException e) {
+                cancel(true);
+            } catch (ExecutionException e) {
+                setException(e.getCause());
+            }
+        }
+    }
+
+    public void getAuthTokenByFeatures(
+            final String accountType, final String authTokenType, final String[] features,
+            final Activity activityForPrompting, final Bundle addAccountOptions,
+            final Bundle loginOptions,
+            final Future2Callback 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,
+                activityForPrompting, addAccountOptions, loginOptions, callback, handler).start();
+    }
+
+    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
+     * in mAccountsUpdatedListeners.
+     */
+    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;
+                    }
+                }
+            }, mMainHandler);
+        }
+    };
+
+    /**
+     * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
+     * The listener is guaranteed to be invoked on the thread of the Handler that is passed
+     * in or the main thread's Handler if handler is null.
+     * @param listener the listener to add
+     * @param handler the Handler whose thread will be used to invoke the listener. If null
+     * the AccountManager context's main thread will be used.
+     * @param updateImmediately if true then the listener will be invoked as a result of this
+     * call.
+     * @throws IllegalArgumentException if listener is null
+     * @throws IllegalStateException if listener was already added
+     */
+    public void addOnAccountsUpdatedListener(final OnAccountsUpdatedListener listener,
+            Handler handler, boolean updateImmediately) {
+        if (listener == null) {
+            throw new IllegalArgumentException("the listener is null");
+        }
+        synchronized (mAccountsUpdatedListeners) {
+            if (mAccountsUpdatedListeners.containsKey(listener)) {
+                throw new IllegalStateException("this listener is already added");
+            }
+            final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
+
+            mAccountsUpdatedListeners.put(listener, handler);
+
+            if (wasEmpty) {
+                // Register a broadcast receiver to monitor account changes
+                IntentFilter intentFilter = new IntentFilter();
+                intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+                mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
+            }
+        }
+
+        if (updateImmediately) {
+            getAccounts(new Future1Callback<Account[]>() {
+                public void run(Future1<Account[]> future) {
+                    try {
+                        listener.onAccountsUpdated(future.getResult());
+                    } catch (OperationCanceledException e) {
+                        // ignore
+                    }
+                }
+            }, handler);
+        }
+    }
+
+    /**
+     * Remove an {@link OnAccountsUpdatedListener} that was previously registered with
+     * {@link #addOnAccountsUpdatedListener}.
+     * @param listener the listener to remove
+     * @throws IllegalArgumentException if listener is null
+     * @throws IllegalStateException if listener was not already added
+     */
+    public void removeOnAccountsUpdatedListener(OnAccountsUpdatedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("the listener is null");
+        }
+        synchronized (mAccountsUpdatedListeners) {
+            if (mAccountsUpdatedListeners.remove(listener) == null) {
+                throw new IllegalStateException("this listener was not previously added");
+            }
+            if (mAccountsUpdatedListeners.isEmpty()) {
+                mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
+            }
+        }
+    }
+}
diff --git a/core/java/android/accounts/AccountManagerResponse.java b/core/java/android/accounts/AccountManagerResponse.java
new file mode 100644
index 0000000..25371fd
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerResponse.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link android.accounts.IAccountManagerResponse} object.
+ * @hide
+ */
+public class AccountManagerResponse implements Parcelable {
+    private IAccountManagerResponse mResponse;
+
+    public AccountManagerResponse(IAccountManagerResponse response) {
+        mResponse = response;
+    }
+
+    public AccountManagerResponse(Parcel parcel) {
+        mResponse =
+                IAccountManagerResponse.Stub.asInterface(parcel.readStrongBinder());
+    }
+
+    public void onResult(Bundle result) {
+        try {
+            mResponse.onResult(result);
+        } catch (RemoteException e) {
+            // this should never happen
+        }
+    }
+
+    public void onError(int errorCode, String errorMessage) {
+        try {
+            mResponse.onError(errorCode, errorMessage);
+        } catch (RemoteException e) {
+            // this should never happen
+        }
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mResponse.asBinder());
+    }
+
+    public static final Creator<AccountManagerResponse> CREATOR =
+            new Creator<AccountManagerResponse>() {
+        public AccountManagerResponse createFromParcel(Parcel source) {
+            return new AccountManagerResponse(source);
+        }
+
+        public AccountManagerResponse[] newArray(int size) {
+            return new AccountManagerResponse[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
new file mode 100644
index 0000000..ef0875c
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -0,0 +1,1187 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.app.NotificationManager;
+import android.app.Notification;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.R;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+/**
+ * A system service that provides  account, password, and authtoken management for all
+ * accounts on the device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
+ * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
+ *    AccountManager accountManager =
+ *      (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
+ * @hide
+ */
+public class AccountManagerService extends IAccountManager.Stub {
+    private static final String TAG = "AccountManagerService";
+
+    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
+    private static final String DATABASE_NAME = "accounts.db";
+    private static final int DATABASE_VERSION = 2;
+
+    private final Context mContext;
+
+    private HandlerThread mMessageThread;
+    private final MessageHandler mMessageHandler;
+
+    // Messages that can be sent on mHandler
+    private static final int MESSAGE_TIMED_OUT = 3;
+    private static final int MESSAGE_CONNECTED = 7;
+    private static final int MESSAGE_DISCONNECTED = 8;
+
+    private final AccountAuthenticatorCache mAuthenticatorCache;
+    private final AuthenticatorBindHelper mBindHelper;
+    private final DatabaseHelper mOpenHelper;
+    private final SimWatcher mSimWatcher;
+
+    private static final String TABLE_ACCOUNTS = "accounts";
+    private static final String ACCOUNTS_ID = "_id";
+    private static final String ACCOUNTS_NAME = "name";
+    private static final String ACCOUNTS_TYPE = "type";
+    private static final String ACCOUNTS_PASSWORD = "password";
+
+    private static final String TABLE_AUTHTOKENS = "authtokens";
+    private static final String AUTHTOKENS_ID = "_id";
+    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
+    private static final String AUTHTOKENS_TYPE = "type";
+    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
+
+    private static final String TABLE_EXTRAS = "extras";
+    private static final String EXTRAS_ID = "_id";
+    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
+    private static final String EXTRAS_KEY = "key";
+    private static final String EXTRAS_VALUE = "value";
+
+    private static final String TABLE_META = "meta";
+    private static final String META_KEY = "key";
+    private static final String META_VALUE = "value";
+
+    private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
+            new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
+    private static final Intent ACCOUNTS_CHANGED_INTENT =
+            new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+
+    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
+    private static final int NOTIFICATION_ID = 234;
+
+    public class AuthTokenKey {
+        public final Account mAccount;
+        public final String mAuthTokenType;
+        private final int mHashCode;
+
+        public AuthTokenKey(Account account, String authTokenType) {
+            mAccount = account;
+            mAuthTokenType = authTokenType;
+            mHashCode = computeHashCode();
+        }
+
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof AuthTokenKey)) {
+                return false;
+            }
+            AuthTokenKey other = (AuthTokenKey)o;
+            if (!mAccount.equals(other.mAccount)) {
+                return false;
+            }
+            return (mAuthTokenType == null)
+                    ? other.mAuthTokenType == null
+                    : mAuthTokenType.equals(other.mAuthTokenType);
+        }
+
+        private int computeHashCode() {
+            int result = 17;
+            result = 31 * result + mAccount.hashCode();
+            result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
+            return result;
+        }
+
+        public int hashCode() {
+            return mHashCode;
+        }
+    }
+
+    public AccountManagerService(Context context) {
+        mContext = context;
+
+        mOpenHelper = new DatabaseHelper(mContext);
+
+        mMessageThread = new HandlerThread("AccountManagerService");
+        mMessageThread.start();
+        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
+
+        mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
+        mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
+                MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
+
+        mSimWatcher = new SimWatcher(mContext);
+    }
+
+    public String getPassword(Account account) {
+        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();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public String getUserData(Account account, String key) {
+        long identityToken = clearCallingIdentity();
+        try {
+            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+            db.beginTransaction();
+            try {
+                long accountId = getAccountId(db, account);
+                if (accountId < 0) {
+                    return null;
+                }
+                Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
+                        EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+                        new String[]{key}, null, null, null);
+                try {
+                    if (cursor.moveToNext()) {
+                        return cursor.getString(0);
+                    }
+                    return null;
+                } finally {
+                    cursor.close();
+                }
+            } finally {
+                db.setTransactionSuccessful();
+                db.endTransaction();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public String[] getAuthenticatorTypes() {
+        long identityToken = clearCallingIdentity();
+        try {
+            Collection<AccountAuthenticatorCache.AuthenticatorInfo> authenticatorCollection =
+                    mAuthenticatorCache.getAllAuthenticators();
+            String[] types = new String[authenticatorCollection.size()];
+            int i = 0;
+            for (AccountAuthenticatorCache.AuthenticatorInfo authenticator : authenticatorCollection) {
+                types[i] = authenticator.mType;
+                i++;
+            }
+            return types;
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public Account[] getAccounts() {
+        long identityToken = clearCallingIdentity();
+        try {
+            return getAccountsByType(null);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public Account[] getAccountsByType(String accountType) {
+        long identityToken = clearCallingIdentity();
+        try {
+            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();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public boolean addAccount(Account account, String password, Bundle extras) {
+        // 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;
+                        }
+                    }
+                }
+                db.setTransactionSuccessful();
+                sendAccountsChangedBroadcast();
+                return true;
+            } finally {
+                db.endTransaction();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
+        ContentValues values = new ContentValues();
+        values.put(EXTRAS_KEY, key);
+        values.put(EXTRAS_ACCOUNTS_ID, accountId);
+        values.put(EXTRAS_VALUE, value);
+        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+    }
+
+    public void removeAccount(Account account) {
+        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();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void invalidateAuthToken(String accountType, String authToken) {
+        long identityToken = clearCallingIdentity();
+        try {
+            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+            db.beginTransaction();
+            try {
+                invalidateAuthToken(db, accountType, authToken);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
+        Cursor cursor = db.rawQuery(
+                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+                        + " FROM " + TABLE_ACCOUNTS
+                        + " JOIN " + TABLE_AUTHTOKENS
+                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+                        + " = " + AUTHTOKENS_ACCOUNTS_ID
+                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
+                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+                new String[]{authToken, accountType});
+        try {
+            while (cursor.moveToNext()) {
+                long authTokenId = cursor.getLong(0);
+                String accountName = cursor.getString(1);
+                String authTokenType = cursor.getString(2);
+                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            long accountId = getAccountId(db, account);
+            if (accountId < 0) {
+                return false;
+            }
+            db.delete(TABLE_AUTHTOKENS,
+                    AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+                    new String[]{type});
+            ContentValues values = new ContentValues();
+            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+            values.put(AUTHTOKENS_TYPE, type);
+            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+            if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+                db.setTransactionSuccessful();
+                return true;
+            }
+            return false;
+        } finally {
+            db.endTransaction();
+        }
+    }
+
+    public String readAuthTokenFromDatabase(Account account, String authTokenType) {
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        db.beginTransaction();
+        try {
+            long accountId = getAccountId(db, account);
+            if (accountId < 0) {
+                return null;
+            }
+            return getAuthToken(db, accountId, authTokenType);
+        } finally {
+            db.setTransactionSuccessful();
+            db.endTransaction();
+        }
+    }
+
+    public String peekAuthToken(Account account, String authTokenType) {
+        long identityToken = clearCallingIdentity();
+        try {
+            return readAuthTokenFromDatabase(account, authTokenType);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void setAuthToken(Account account, String authTokenType, String authToken) {
+        long identityToken = clearCallingIdentity();
+        try {
+            cacheAuthToken(account, authTokenType, authToken);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void setPassword(Account account, String password) {
+        long identityToken = clearCallingIdentity();
+        try {
+            ContentValues values = new ContentValues();
+            values.put(ACCOUNTS_PASSWORD, password);
+            mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                    new String[]{account.mName, account.mType});
+            sendAccountsChangedBroadcast();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private void sendAccountsChangedBroadcast() {
+        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
+    }
+
+    public void clearPassword(Account account) {
+        long identityToken = clearCallingIdentity();
+        try {
+            setPassword(account, null);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void setUserData(Account account, String key, String value) {
+        long identityToken = clearCallingIdentity();
+        try {
+            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+            db.beginTransaction();
+            try {
+                long accountId = getAccountId(db, account);
+                if (accountId < 0) {
+                    return;
+                }
+                long extrasId = getExtrasId(db, accountId, key);
+                if (extrasId < 0 ) {
+                    extrasId = insertExtra(db, accountId, key, value);
+                    if (extrasId < 0) {
+                        return;
+                    }
+                } else {
+                    ContentValues values = new ContentValues();
+                    values.put(EXTRAS_VALUE, value);
+                    if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+                        return;
+                    }
+
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void getAuthToken(IAccountManagerResponse response, final Account account,
+            final String authTokenType, final boolean notifyOnAuthFailure,
+            final boolean expectActivityLaunch, final Bundle loginOptions) {
+        long identityToken = clearCallingIdentity();
+        try {
+            String authToken = readAuthTokenFromDatabase(account, authTokenType);
+            if (authToken != null) {
+                try {
+                    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);
+                    response.onResult(result);
+                } 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);
+                    }
+                }
+                return;
+            }
+
+            new Session(response, account.mType, expectActivityLaunch) {
+                protected String toDebugString(long now) {
+                    if (loginOptions != null) loginOptions.keySet();
+                    return super.toDebugString(now) + ", getAuthToken"
+                            + ", " + account
+                            + ", authTokenType " + authTokenType
+                            + ", loginOptions " + loginOptions
+                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
+                }
+
+                public void run() throws RemoteException {
+                    mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
+                }
+
+                public void onResult(Bundle result) {
+                    if (result != null) {
+                        String authToken = result.getString(Constants.AUTHTOKEN_KEY);
+                        if (authToken != null) {
+                            String name = result.getString(Constants.ACCOUNT_NAME_KEY);
+                            String type = result.getString(Constants.ACCOUNT_TYPE_KEY);
+                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
+                                onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+                                        "the type and name should not be empty");
+                                return;
+                            }
+                            cacheAuthToken(new Account(name, type), authTokenType, authToken);
+                        }
+
+                        Intent intent = result.getParcelable(Constants.INTENT_KEY);
+                        if (intent != null && notifyOnAuthFailure) {
+                            doNotification(result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
+                                    intent);
+                        }
+                    }
+                    super.onResult(result);
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+
+    public void addAcount(final IAccountManagerResponse response, final String accountType,
+            final String authTokenType, final String[] requiredFeatures,
+            final boolean expectActivityLaunch, final Bundle options) {
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(response, accountType, expectActivityLaunch) {
+                public void run() throws RemoteException {
+                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, 
+                            options);
+                }
+
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", addAccount"
+                            + ", accountType " + accountType
+                            + ", requiredFeatures "
+                            + (requiredFeatures != null
+                              ? TextUtils.join(",", requiredFeatures)
+                              : null);
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void confirmCredentials(IAccountManagerResponse response,
+            final Account account, final boolean expectActivityLaunch) {
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(response, account.mType, expectActivityLaunch) {
+                public void run() throws RemoteException {
+                    mAuthenticator.confirmCredentials(this, account);
+                }
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", confirmCredentials"
+                            + ", " + account;
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void confirmPassword(IAccountManagerResponse response, final Account account,
+            final String password) {
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(response, account.mType, false /* expectActivityLaunch */) {
+                public void run() throws RemoteException {
+                    mAuthenticator.confirmPassword(this, account, password);
+                }
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", confirmPassword"
+                            + ", " + account;
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void updateCredentials(IAccountManagerResponse response, final Account account,
+            final String authTokenType, final boolean expectActivityLaunch,
+            final Bundle loginOptions) {
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(response, account.mType, expectActivityLaunch) {
+                public void run() throws RemoteException {
+                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
+                }
+                protected String toDebugString(long now) {
+                    if (loginOptions != null) loginOptions.keySet();
+                    return super.toDebugString(now) + ", updateCredentials"
+                            + ", " + account
+                            + ", authTokenType " + authTokenType
+                            + ", loginOptions " + loginOptions;
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    public void editProperties(IAccountManagerResponse response, final String accountType,
+            final boolean expectActivityLaunch) {
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(response, accountType, expectActivityLaunch) {
+                public void run() throws RemoteException {
+                    mAuthenticator.editProperties(this, mAccountType);
+                }
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", editProperties"
+                            + ", accountType " + accountType;
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private class GetAccountsByTypeAndFeatureSession extends Session {
+        private final String[] mFeatures;
+        private volatile Account[] mAccountsOfType = null;
+        private volatile ArrayList<Account> mAccountsWithFeatures = null;
+        private volatile int mCurrentAccount = 0;
+
+        public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
+            String type, String[] features) {
+            super(response, type, false /* expectActivityLaunch */);
+            mFeatures = features;
+        }
+
+        public void run() throws RemoteException {
+            mAccountsOfType = getAccountsByType(mAccountType);
+            // check whether each account matches the requested features
+            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
+            mCurrentAccount = 0;
+
+            checkAccount();
+        }
+
+        public void checkAccount() {
+            if (mCurrentAccount >= mAccountsOfType.length) {
+                sendResult();
+                return;
+            }
+
+            try {
+                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
+            } catch (RemoteException e) {
+                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
+            }
+        }
+
+        public void onResult(Bundle result) {
+            mNumResults++;
+            if (result == null) {
+                onError(Constants.ERROR_CODE_INVALID_RESPONSE, "null bundle");
+                return;
+            }
+            if (result.getBoolean(Constants.BOOLEAN_RESULT_KEY, false)) {
+                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
+            }
+            mCurrentAccount++;
+            checkAccount();
+        }
+
+        public void sendResult() {
+            IAccountManagerResponse response = getResponseAndClose();
+            if (response != null) {
+                try {
+                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
+                    for (int i = 0; i < accounts.length; i++) {
+                        accounts[i] = mAccountsWithFeatures.get(i);
+                    }
+                    Bundle result = new Bundle();
+                    result.putParcelableArray(Constants.ACCOUNTS_KEY, accounts);
+                    response.onResult(result);
+                } 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);
+                    }
+                }
+            }
+        }
+
+
+        protected String toDebugString(long now) {
+            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
+                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
+        }
+    }
+    public void getAccountsByTypeAndFeatures(IAccountManagerResponse response,
+            String type, String[] features) {
+        if (type == null) {
+            if (response != null) {
+                try {
+                    response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
+                } catch (RemoteException e) {
+                    // ignore this
+                }
+            }
+            return;
+        }
+        long identityToken = clearCallingIdentity();
+        try {
+            new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
+        return saveAuthTokenToDatabase(account, authTokenType, authToken);
+    }
+
+    private long getAccountId(SQLiteDatabase db, Account account) {
+        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
+                "name=? AND type=?", new String[]{account.mName, account.mType}, null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+            return -1;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
+        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+                new String[]{key}, null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            }
+            return -1;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
+        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
+                AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+                new String[]{authTokenType},
+                null, null, null);
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
+            }
+            return null;
+        } finally {
+            cursor.close();
+        }
+    }
+
+    private abstract class Session extends IAccountAuthenticatorResponse.Stub
+            implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
+        IAccountManagerResponse mResponse;
+        final String mAccountType;
+        final boolean mExpectActivityLaunch;
+        final long mCreationTime;
+
+        public int mNumResults = 0;
+        private int mNumRequestContinued = 0;
+        private int mNumErrors = 0;
+
+
+        IAccountAuthenticator mAuthenticator = null;
+
+        public Session(IAccountManagerResponse response, String accountType,
+                boolean expectActivityLaunch) {
+            super();
+            if (response == null) throw new IllegalArgumentException("response is null");
+            if (accountType == null) throw new IllegalArgumentException("accountType is null");
+            mResponse = response;
+            mAccountType = accountType;
+            mExpectActivityLaunch = expectActivityLaunch;
+            mCreationTime = SystemClock.elapsedRealtime();
+            synchronized (mSessions) {
+                mSessions.put(toString(), this);
+            }
+            try {
+                response.asBinder().linkToDeath(this, 0 /* flags */);
+            } catch (RemoteException e) {
+                mResponse = null;
+                binderDied();
+            }
+        }
+
+        IAccountManagerResponse getResponseAndClose() {
+            if (mResponse == null) {
+                // this session has already been closed
+                return null;
+            }
+            IAccountManagerResponse response = mResponse;
+            close(); // this clears mResponse so we need to save the response before this call
+            return response;
+        }
+
+        private void close() {
+            synchronized (mSessions) {
+                if (mSessions.remove(toString()) == null) {
+                    // the session was already closed, so bail out now
+                    return;
+                }
+            }
+            if (mResponse != null) {
+                // stop listening for response deaths
+                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
+
+                // clear this so that we don't accidentally send any further results
+                mResponse = null;
+            }
+            cancelTimeout();
+            unbind();
+        }
+
+        public void binderDied() {
+            mResponse = null;
+            close();
+        }
+
+        protected String toDebugString() {
+            return toDebugString(SystemClock.elapsedRealtime());
+        }
+
+        protected String toDebugString(long now) {
+            return "Session: expectLaunch " + mExpectActivityLaunch
+                    + ", connected " + (mAuthenticator != null)
+                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
+                    + "/" + mNumErrors + ")"
+                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
+        }
+
+        void bind() {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
+            }
+            if (!mBindHelper.bind(mAccountType, this)) {
+                Log.d(TAG, "bind attempt failed for " + toDebugString());
+                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
+            }
+        }
+
+        private void unbind() {
+            if (mAuthenticator != null) {
+                mAuthenticator = null;
+                mBindHelper.unbind(this);
+            }
+        }
+
+        public void scheduleTimeout() {
+            mMessageHandler.sendMessageDelayed(
+                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
+        }
+
+        public void cancelTimeout() {
+            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
+        }
+
+        public void onConnected(IBinder service) {
+            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
+            try {
+                run();
+            } catch (RemoteException e) {
+                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+                        "remote exception");
+            }
+        }
+
+        public abstract void run() throws RemoteException;
+
+        public void onDisconnected() {
+            mAuthenticator = null;
+            IAccountManagerResponse response = getResponseAndClose();
+            if (response != null) {
+                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+                        "disconnected");
+            }
+        }
+
+        public void onTimedOut() {
+            IAccountManagerResponse response = getResponseAndClose();
+            if (response != null) {
+                onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+                        "timeout");
+            }
+        }
+
+        public void onResult(Bundle result) {
+            mNumResults++;
+            if (result != null && !TextUtils.isEmpty(result.getString(Constants.AUTHTOKEN_KEY))) {
+                cancelNotification();
+            }
+            IAccountManagerResponse response;
+            if (mExpectActivityLaunch && result != null
+                    && result.containsKey(Constants.INTENT_KEY)) {
+                response = mResponse;
+            } else {
+                response = getResponseAndClose();
+            }
+            if (response != null) {
+                try {
+                    if (result == null) {
+                        response.onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+                                "null bundle returned");
+                    } else {
+                        response.onResult(result);
+                    }
+                } 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 onRequestContinued() {
+            mNumRequestContinued++;
+        }
+
+        public void onError(int errorCode, String errorMessage) {
+            mNumErrors++;
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
+            }
+            IAccountManagerResponse response = getResponseAndClose();
+            if (response != null) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Session.onError: responding");
+                }
+                try {
+                    response.onError(errorCode, errorMessage);
+                } catch (RemoteException e) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
+                    }
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Session.onError: already closed");
+                }
+            }
+        }
+    }
+
+    private class MessageHandler extends Handler {
+        MessageHandler(Looper looper) {
+            super(looper);
+        }
+        
+        public void handleMessage(Message msg) {
+            if (mBindHelper.handleMessage(msg)) {
+                return;
+            }
+            switch (msg.what) {
+                case MESSAGE_TIMED_OUT:
+                    Session session = (Session)msg.obj;
+                    session.onTimedOut();
+                    break;
+
+                default:
+                    throw new IllegalStateException("unhandled message: " + msg.what);
+            }
+        }
+    }
+
+    private class DatabaseHelper extends SQLiteOpenHelper {
+        public DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + ACCOUNTS_PASSWORD + " TEXT, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
+                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
+                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
+                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+                    + EXTRAS_KEY + " TEXT NOT NULL, "
+                    + EXTRAS_VALUE + " TEXT, "
+                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+                    + META_VALUE + " TEXT)");
+
+            db.execSQL(""
+                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                    + " BEGIN"
+                    + "   DELETE FROM " + TABLE_AUTHTOKENS
+                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + "   DELETE FROM " + TABLE_EXTRAS
+                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+                    + " END");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+            if (oldVersion == 1) {
+                db.execSQL(""
+                        + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+                        + " BEGIN"
+                        + "   DELETE FROM " + TABLE_AUTHTOKENS
+                        + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + " =OLD." + ACCOUNTS_ID + " ;"
+                        + "   DELETE FROM " + TABLE_EXTRAS
+                        + "     WHERE " + EXTRAS_ACCOUNTS_ID + " =OLD." + ACCOUNTS_ID + " ;"
+                        + " END");
+                oldVersion++;
+            }
+        }
+
+        @Override
+        public void onOpen(SQLiteDatabase db) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
+        }
+    }
+
+    private void setMetaValue(String key, String value) {
+        ContentValues values = new ContentValues();
+        values.put(META_KEY, key);
+        values.put(META_VALUE, value);
+        mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
+    }
+
+    private String getMetaValue(String key) {
+        Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
+                new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
+        try {
+            if (c.moveToNext()) {
+                return c.getString(0);
+            }
+            return null;
+        } finally {
+            c.close();
+        }
+    }
+
+    private class SimWatcher extends BroadcastReceiver {
+        public SimWatcher(Context context) {
+            // Re-scan the SIM card when the SIM state changes, and also if
+            // the disk recovers from a full state (we may have failed to handle
+            // things properly while the disk was full).
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+            filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
+            context.registerReceiver(this, filter);
+        }
+        
+        /**
+         * Compare the IMSI to the one stored in the login service's
+         * database.  If they differ, erase all passwords and
+         * authtokens (and store the new IMSI).
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
+            String imsi = ((TelephonyManager) context.getSystemService(
+                    Context.TELEPHONY_SERVICE)).getSubscriberId();
+            if (TextUtils.isEmpty(imsi)) return;
+
+            String storedImsi = getMetaValue("imsi");
+
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
+            }
+
+            if (!imsi.equals(storedImsi) && !"initial".equals(storedImsi)) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "wiping all passwords and authtokens");
+                }
+                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+                db.beginTransaction();
+                try {
+                    db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
+                    db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
+                    sendAccountsChangedBroadcast();
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            setMetaValue("imsi", imsi);
+        }
+    }
+
+    public IBinder onBind(Intent intent) {
+        return asBinder();
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        synchronized (mSessions) {
+            final long now = SystemClock.elapsedRealtime();
+            fout.println("AccountManagerService: " + mSessions.size() + " sessions");
+            for (Session session : mSessions.values()) {
+                fout.println("  " + session.toDebugString(now));
+            }
+        }
+
+        fout.println();
+
+        mAuthenticatorCache.dump(fd, fout, args);
+    }
+
+    private void doNotification(CharSequence message, Intent intent) {
+        long identityToken = clearCallingIdentity();
+        try {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
+            }
+
+            Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
+                    0 /* when */);
+            n.setLatestEventInfo(mContext, mContext.getText(R.string.notification_title), message,
+                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
+            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+                    .notify(NOTIFICATION_ID, n);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private void cancelNotification() {
+        long identityToken = clearCallingIdentity();
+        try {
+            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+                .cancel(NOTIFICATION_ID);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+}
diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java
deleted file mode 100644
index f21385e..0000000
--- a/core/java/android/accounts/AccountMonitor.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.database.SQLException;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * A helper class that calls back on the provided
- * AccountMonitorListener with the set of current accounts both when
- * it gets created and whenever the set changes. It does this by
- * binding to the AccountsService and registering to receive the
- * intent broadcast when the set of accounts is changed.  The
- * connection to the accounts service is only made when it needs to
- * fetch the current list of accounts (that is, when the
- * AccountMonitor is first created, and when the intent is received).
- */
-public class AccountMonitor extends BroadcastReceiver implements ServiceConnection {
-    private final Context mContext;
-    private final AccountMonitorListener mListener;
-    private boolean mClosed = false;
-    private int pending = 0;
-
-    // This thread runs in the background and runs the code to update accounts
-    // in the listener.
-    private class AccountUpdater extends Thread {
-        private IBinder mService;
-
-        public AccountUpdater(IBinder service) {
-            mService = service;
-        }
-
-        @Override
-        public void run() {
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            IAccountsService accountsService = IAccountsService.Stub.asInterface(mService);
-            String[] accounts = null;
-            do {
-                try {
-                    accounts = accountsService.getAccounts();
-                } catch (RemoteException e) {
-                    // if the service was killed then the system will restart it and when it does we
-                    // will get another onServiceConnected, at which point we will do a notify.
-                    Log.w("AccountMonitor", "Remote exception when getting accounts", e);
-                    return;
-                }
-
-                synchronized (AccountMonitor.this) {
-                    --pending;
-                    if (pending == 0) {
-                        break;
-                    }
-                }
-            } while (true);
-
-            mContext.unbindService(AccountMonitor.this);
-
-            try {
-                mListener.onAccountsUpdated(accounts);
-            } catch (SQLException e) {
-                // Better luck next time.  If the problem was disk-full,
-                // the STORAGE_OK intent will re-trigger the update.
-                Log.e("AccountMonitor", "Can't update accounts", e);
-            }
-        }
-    }
-
-    /**
-     * Initializes the AccountMonitor and initiates a bind to the
-     * AccountsService to get the initial account list.  For 1.0,
-     * the "list" is always a single account.
-     *
-     * @param context the context we are running in
-     * @param listener the user to notify when the account set changes
-     */
-    public AccountMonitor(Context context, AccountMonitorListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener is null");
-        }
-
-        mContext = context;
-        mListener = listener;
-
-        // Register a broadcast receiver to monitor account changes
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION);
-        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);  // To recover from disk-full.
-        mContext.registerReceiver(this, intentFilter);
-
-        // Send the listener the initial state now.
-        notifyListener();
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        notifyListener();
-    }
-
-    public void onServiceConnected(ComponentName className, IBinder service) {
-        // Create a background thread to update the accounts.
-        new AccountUpdater(service).start();
-    }
-
-    public void onServiceDisconnected(ComponentName className) {
-    }
-
-    private synchronized void notifyListener() {
-        if (pending == 0) {
-            // initiate the bind
-            if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
-                                      this, Context.BIND_AUTO_CREATE)) {
-                // This is normal if GLS isn't part of this build.
-                Log.w("AccountMonitor",
-                      "Couldn't connect to "  +
-                      AccountsServiceConstants.SERVICE_INTENT +
-                      " (Missing service?)");
-            }
-        } else {
-            // already bound.  bindService will not trigger another
-            // call to onServiceConnected, so instead we make sure
-            // that the existing background thread will call
-            // getAccounts() after this function returns, by
-            // incrementing pending.
-            //
-            // Yes, this else clause contains only a comment.
-        }
-        ++pending;
-    }
-
-    /**
-     * calls close()
-     * @throws Throwable
-     */
-    @Override
-    protected void finalize() throws Throwable {
-        close();
-        super.finalize();
-    }
-
-    /**
-     * Unregisters the account receiver.  Consecutive calls to this
-     * method are harmless, but also do nothing.  Once this call is
-     * made no more notifications will occur.
-     */
-    public synchronized void close() {
-        if (!mClosed) {
-            mContext.unregisterReceiver(this);
-            mClosed = true;
-        }
-    }
-}
diff --git a/core/java/android/accounts/AccountsServiceConstants.java b/core/java/android/accounts/AccountsServiceConstants.java
deleted file mode 100644
index b882e7b..0000000
--- a/core/java/android/accounts/AccountsServiceConstants.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-import android.content.Intent;
-
-/**
- * Miscellaneous constants used by the AccountsService and its
- * clients.
- */
-// TODO: These constants *could* come directly from the
-// IAccountsService interface, but that's not possible since the
-// aidl compiler doesn't let you define constants (yet.)
-public class AccountsServiceConstants {
-    /** This class is never instantiated. */
-    private AccountsServiceConstants() {
-    }
-
-    /**
-     * Action sent as a broadcast Intent by the AccountsService
-     * when accounts are added to and/or removed from the device's
-     * database, or when the primary account is changed.
-     */
-    public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
-        "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-
-    /**
-     * Action sent as a broadcast Intent by the AccountsService
-     * when it starts up and no accounts are available (so some should be added).
-     */
-    public static final String LOGIN_ACCOUNTS_MISSING_ACTION =
-        "android.accounts.LOGIN_ACCOUNTS_MISSING";
-
-    /**
-     * Action on the intent used to bind to the IAccountsService interface. This
-     * is used for services that have multiple interfaces (allowing
-     * them to differentiate the interface intended, and return the proper
-     * Binder.)
-     */
-    private static final String ACCOUNTS_SERVICE_ACTION = "android.accounts.IAccountsService";
-
-    /*
-     * The intent uses a component in addition to the action to ensure the actual
-     * accounts service is bound to (a malicious third-party app could
-     * theoretically have a service with the same action).
-     */
-    /** The intent used to bind to the accounts service. */
-    public static final Intent SERVICE_INTENT =
-        new Intent()
-            .setClassName("com.google.android.googleapps",
-                    "com.google.android.googleapps.GoogleLoginService")
-            .setAction(ACCOUNTS_SERVICE_ACTION);
-
-    /**
-     * Checks whether the intent is to bind to the accounts service.
-     * 
-     * @param bindIntent The Intent used to bind to the service. 
-     * @return Whether the intent is to bind to the accounts service.
-     */
-    public static final boolean isForAccountsService(Intent bindIntent) {
-        String otherAction = bindIntent.getAction();
-        return otherAction != null && otherAction.equals(ACCOUNTS_SERVICE_ACTION);
-    }
-}
diff --git a/core/java/android/accounts/AuthenticatorBindHelper.java b/core/java/android/accounts/AuthenticatorBindHelper.java
new file mode 100644
index 0000000..6c28485
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorBindHelper.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+/**
+ * A helper object that simplifies binding to Account Authenticators. It uses the
+ * {@link AccountAuthenticatorCache} to find the component name of the authenticators,
+ * allowing the user to bind by account name. It also allows multiple, simultaneous binds
+ * to the same authenticator, with each bind call guaranteed to return either
+ * {@link Callback#onConnected} or {@link Callback#onDisconnected} if the bind() call
+ * itself succeeds, even if the authenticator is already bound internally.
+ */
+public class AuthenticatorBindHelper {
+    private static final String TAG = "Accounts";
+    private final Handler mHandler;
+    private final Context mContext;
+    private final int mMessageWhatConnected;
+    private final int mMessageWhatDisconnected;
+    private final Map<String, MyServiceConnection> mServiceConnections = Maps.newHashMap();
+    private final Map<String, ArrayList<Callback>> mServiceUsers = Maps.newHashMap();
+    private final AccountAuthenticatorCache mAuthenticatorCache;
+
+    public AuthenticatorBindHelper(Context context,
+            AccountAuthenticatorCache authenticatorCache, Handler handler,
+            int messageWhatConnected, int messageWhatDisconnected) {
+        mContext = context;
+        mHandler = handler;
+        mAuthenticatorCache = authenticatorCache;
+        mMessageWhatConnected = messageWhatConnected;
+        mMessageWhatDisconnected = messageWhatDisconnected;
+    }
+
+    public interface Callback {
+        void onConnected(IBinder service);
+        void onDisconnected();
+    }
+
+    public boolean bind(String authenticatorType, Callback callback) {
+        // if the authenticator is connecting or connected then return true
+        synchronized (mServiceConnections) {
+            if (mServiceConnections.containsKey(authenticatorType)) {
+                MyServiceConnection connection = mServiceConnections.get(authenticatorType);
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "service connection already exists for " + authenticatorType);
+                }
+                mServiceUsers.get(authenticatorType).add(callback);
+                if (connection.mService != null) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "the service is connected, scheduling a connected message for "
+                                + authenticatorType);
+                    }
+                    connection.scheduleCallbackConnectedMessage(callback);
+                } else {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "the service is *not* connected, waiting for for "
+                                + authenticatorType);
+                    }
+                }
+                return true;
+            }
+
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "there is no service connection for " + authenticatorType);
+            }
+
+            // otherwise find the component name for the authenticator and initiate a bind
+            // if no authenticator or the bind fails then return false, otherwise return true
+            AccountAuthenticatorCache.AuthenticatorInfo authenticatorInfo =
+                    mAuthenticatorCache.getAuthenticatorInfo(authenticatorType);
+            if (authenticatorInfo == null) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "there is no authenticator for " + authenticatorType
+                            + ", bailing out");
+                }
+                return false;
+            }
+
+            MyServiceConnection connection = new MyServiceConnection(authenticatorType);
+
+            Intent intent = new Intent();
+            intent.setAction("android.accounts.AccountAuthenticator");
+            intent.setComponent(authenticatorInfo.mComponentName);
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "performing bindService to " + authenticatorInfo.mComponentName);
+            }
+            if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "bindService to " + authenticatorInfo.mComponentName + " failed");
+                }
+                return false;
+            }
+
+            mServiceConnections.put(authenticatorType, connection);
+            mServiceUsers.put(authenticatorType, Lists.newArrayList(callback));
+            return true;
+        }
+    }
+
+    public void unbind(Callback callbackToUnbind) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "unbinding callback " + callbackToUnbind);
+        }
+        synchronized (mServiceConnections) {
+            for (Map.Entry<String, ArrayList<Callback>> entry : mServiceUsers.entrySet()) {
+                final String authenticatorType = entry.getKey();
+                final ArrayList<Callback> serviceUsers = entry.getValue();
+                for (Callback callback : serviceUsers) {
+                    if (callback == callbackToUnbind) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "found callback in service" + authenticatorType);
+                        }
+                        serviceUsers.remove(callbackToUnbind);
+                        if (serviceUsers.isEmpty()) {
+                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                                Log.v(TAG, "there are no more callbacks for service "
+                                        + authenticatorType + ", unbinding service");
+                            }
+                            unbindFromService(authenticatorType);
+                        } else {
+                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                                Log.v(TAG, "leaving service " + authenticatorType
+                                        + " around since there are still callbacks using it");
+                            }
+                        }
+                        return;
+                    }
+                }
+            }
+            Log.e(TAG, "did not find callback " + callbackToUnbind + " in any of the services");
+        }
+    }
+
+    private void unbindFromService(String authenticatorType) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "unbindService from " + authenticatorType);
+        }
+        mContext.unbindService(mServiceConnections.get(authenticatorType));
+        mServiceUsers.remove(authenticatorType);
+        mServiceConnections.remove(authenticatorType);
+    }
+
+    private class ConnectedMessagePayload {
+        public final IBinder mService;
+        public final Callback mCallback;
+        public ConnectedMessagePayload(IBinder service, Callback callback) {
+            mService = service;
+            mCallback = callback;
+        }
+    }
+
+    private class MyServiceConnection implements ServiceConnection {
+        private final String mAuthenticatorType;
+        private IBinder mService = null;
+
+        public MyServiceConnection(String authenticatorType) {
+            mAuthenticatorType = authenticatorType;
+        }
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "onServiceConnected for account type " + mAuthenticatorType);
+            }
+            // post a message for each service user to tell them that the service is connected
+            synchronized (mServiceConnections) {
+                mService = service;
+                for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "the service became connected, scheduling a connected "
+                                + "message for " + mAuthenticatorType);
+                    }
+                    scheduleCallbackConnectedMessage(callback);
+                }
+            }
+        }
+
+        private void scheduleCallbackConnectedMessage(Callback callback) {
+            final ConnectedMessagePayload payload =
+                    new ConnectedMessagePayload(mService, callback);
+            mHandler.obtainMessage(mMessageWhatConnected, payload).sendToTarget();
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "onServiceDisconnected for account type " + mAuthenticatorType);
+            }
+            // post a message for each service user to tell them that the service is disconnected,
+            // and unbind from the service.
+            synchronized (mServiceConnections) {
+                for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "the service became disconnected, scheduling a "
+                                + "disconnected message for "
+                                + mAuthenticatorType);
+                    }
+                    mHandler.obtainMessage(mMessageWhatDisconnected, callback).sendToTarget();
+                }
+                unbindFromService(mAuthenticatorType);
+            }
+        }
+    }
+
+    boolean handleMessage(Message message) {
+        if (message.what == mMessageWhatConnected) {
+            ConnectedMessagePayload payload = (ConnectedMessagePayload)message.obj;
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "notifying callback " + payload.mCallback + " that it is connected");
+            }
+            payload.mCallback.onConnected(payload.mService);
+            return true;
+        } else if (message.what == mMessageWhatDisconnected) {
+            Callback callback = (Callback)message.obj;
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "notifying callback " + callback + " that it is disconnected");
+            }
+            callback.onDisconnected();
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/core/java/android/accounts/AuthenticatorException.java b/core/java/android/accounts/AuthenticatorException.java
new file mode 100644
index 0000000..4023494
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+public class AuthenticatorException extends Exception {
+    public AuthenticatorException() {
+        super();
+    }
+    public AuthenticatorException(String message) {
+        super(message);
+    }
+    public AuthenticatorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+    public AuthenticatorException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
new file mode 100644
index 0000000..83377f3
--- /dev/null
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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.app.ListActivity;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.view.View;
+import android.util.Log;
+
+public class ChooseAccountActivity extends ListActivity {
+    private static final String TAG = "AccountManager";
+    private Parcelable[] mAccounts = null;
+    private AccountManagerResponse mAccountManagerResponse = null;
+    private Bundle mResult;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            mAccounts = getIntent().getParcelableArrayExtra(Constants.ACCOUNTS_KEY);
+            mAccountManagerResponse =
+                    getIntent().getParcelableExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+        } else {
+            mAccounts = savedInstanceState.getParcelableArray(Constants.ACCOUNTS_KEY);
+            mAccountManagerResponse =
+                    savedInstanceState.getParcelable(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+        }
+
+        String[] mAccountNames = new String[mAccounts.length];
+        for (int i = 0; i < mAccounts.length; i++) {
+            mAccountNames[i] = ((Account) mAccounts[i]).mName;
+        }
+
+        // Use an existing ListAdapter that will map an array
+        // of strings to TextViews
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, mAccountNames));
+        getListView().setTextFilterEnabled(true);
+    }
+
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        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);
+        mResult = bundle;
+        finish();
+    }
+
+    public void finish() {
+        if (mAccountManagerResponse != null) {
+            if (mResult != null) {
+                mAccountManagerResponse.onResult(mResult);
+            } else {
+                mAccountManagerResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+            }
+        }
+        super.finish();
+    }
+}
diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java
new file mode 100644
index 0000000..b383c61
--- /dev/null
+++ b/core/java/android/accounts/Constants.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+public class Constants {
+    // this should never be instantiated
+    private Constants() {}
+
+    public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
+    public static final int ERROR_CODE_NETWORK_ERROR = 3;
+    public static final int ERROR_CODE_CANCELED = 4;
+    public static final int ERROR_CODE_INVALID_RESPONSE = 5;
+    public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
+    public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
+
+    public static final String ACCOUNTS_KEY = "accounts";
+    public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types";
+    public static final String PASSWORD_KEY = "password";
+    public static final String USERDATA_KEY = "userdata";
+    public static final String AUTHTOKEN_KEY = "authtoken";
+    public static final String ACCOUNT_NAME_KEY = "authAccount";
+    public static final String ACCOUNT_TYPE_KEY = "accountType";
+    public static final String ERROR_CODE_KEY = "errorCode";
+    public static final String ERROR_MESSAGE_KEY = "errorMessage";
+    public static final String INTENT_KEY = "intent";
+    public static final String BOOLEAN_RESULT_KEY = "booleanResult";
+    public static final String ACCOUNT_AUTHENTICATOR_RESPONSE_KEY = "accountAuthenticatorResponse";
+    public static final String ACCOUNT_MANAGER_RESPONSE_KEY = "accountManagerResponse";
+    public static final String AUTH_FAILED_MESSAGE_KEY = "authFailedMessage";
+    /**
+     * Action sent as a broadcast Intent by the AccountsService
+     * when accounts are added to and/or removed from the device's
+     * database, or when the primary account is changed.
+     */
+    public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
+        "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+}
diff --git a/core/java/android/accounts/Future1.java b/core/java/android/accounts/Future1.java
new file mode 100644
index 0000000..386cb6e
--- /dev/null
+++ b/core/java/android/accounts/Future1.java
@@ -0,0 +1,46 @@
+/*
+ * 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/AccountMonitorListener.java b/core/java/android/accounts/Future1Callback.java
similarity index 60%
copy from core/java/android/accounts/AccountMonitorListener.java
copy to core/java/android/accounts/Future1Callback.java
index d0bd9a9..886671b 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/Future1Callback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -13,17 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.accounts;
 
-/**
- * An interface that contains the callback used by the AccountMonitor
- */
-public interface AccountMonitorListener {
-    /**
-     * This invoked when the AccountMonitor starts up and whenever the account
-     * set changes.
-     * @param currentAccounts the current accounts
-     */
-    void onAccountsUpdated(String[] currentAccounts);
+public interface Future1Callback<V> {
+    void run(Future1<V> future);
 }
diff --git a/core/java/android/accounts/Future2.java b/core/java/android/accounts/Future2.java
new file mode 100644
index 0000000..b2ea84f
--- /dev/null
+++ b/core/java/android/accounts/Future2.java
@@ -0,0 +1,57 @@
+/*
+ * 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/Future2Callback.java b/core/java/android/accounts/Future2Callback.java
new file mode 100644
index 0000000..7ef0c94
--- /dev/null
+++ b/core/java/android/accounts/Future2Callback.java
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+public interface Future2Callback {
+    void run(Future2 future);
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
new file mode 100644
index 0000000..46a7144
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.accounts.IAccountAuthenticatorResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Service that allows the interaction with an authentication server.
+ */
+oneway interface IAccountAuthenticator {
+    /**
+     * prompts the user for account information and adds the result to the IAccountManager
+     */
+    void addAccount(in IAccountAuthenticatorResponse response, String accountType,
+        String authTokenType, in String[] requiredFeatures, in Bundle options);
+
+    /**
+     * Checks that the account/password combination is valid.
+     * @deprecated
+     */
+    void confirmPassword(in IAccountAuthenticatorResponse response,
+        in Account account, String password);
+
+    /**
+     * prompts the user for the credentials of the account
+     */
+    void confirmCredentials(in IAccountAuthenticatorResponse response, in Account account);
+
+    /**
+     * gets the password by either prompting the user or querying the IAccountManager
+     */
+    void getAuthToken(in IAccountAuthenticatorResponse response, in Account account,
+        String authTokenType, in Bundle options);
+
+    /**
+     * prompts the user for a new password and writes it to the IAccountManager
+     */
+    void updateCredentials(in IAccountAuthenticatorResponse response, in Account account,
+        String authTokenType, in Bundle options);
+
+    /**
+     * launches an activity that lets the user edit and set the properties for an authenticator
+     */
+    void editProperties(in IAccountAuthenticatorResponse response, String accountType);
+
+    /**
+     * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
+     * specified features
+     */
+    void hasFeatures(in IAccountAuthenticatorResponse response, in Account account, 
+        in String[] features);
+}
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
similarity index 60%
copy from core/java/android/accounts/AccountMonitorListener.java
copy to core/java/android/accounts/IAccountAuthenticatorResponse.aidl
index d0bd9a9..a9ac2f1 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -15,15 +15,13 @@
  */
 
 package android.accounts;
+import android.os.Bundle;
 
 /**
- * An interface that contains the callback used by the AccountMonitor
+ * The interface used to return responses from an {@link IAccountAuthenticator}
  */
-public interface AccountMonitorListener {
-    /**
-     * This invoked when the AccountMonitor starts up and whenever the account
-     * set changes.
-     * @param currentAccounts the current accounts
-     */
-    void onAccountsUpdated(String[] currentAccounts);
+oneway interface IAccountAuthenticatorResponse {
+    void onResult(in Bundle value);
+    void onRequestContinued();
+    void onError(int errorCode, String errorMessage);
 }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
new file mode 100644
index 0000000..5e37a1f
--- /dev/null
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+import android.accounts.IAccountManagerResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Central application service that provides account management.
+ * @hide
+ */
+interface IAccountManager {
+    String getPassword(in Account account);
+    String getUserData(in Account account, String key);
+    String[] getAuthenticatorTypes();
+    Account[] getAccounts();
+    Account[] getAccountsByType(String accountType);
+    boolean addAccount(in Account account, String password, in Bundle extras);
+    void removeAccount(in Account account);
+    void invalidateAuthToken(String accountType, String authToken);
+    String peekAuthToken(in Account account, String authTokenType);
+    void setAuthToken(in Account account, String authTokenType, String authToken);
+    void setPassword(in Account account, String password);
+    void clearPassword(in Account account);
+    void setUserData(in Account account, String key, String value);
+
+    void getAuthToken(in IAccountManagerResponse response, in Account account,
+        String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
+        in Bundle options);
+    void addAcount(in IAccountManagerResponse response, String accountType,
+        String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch, 
+        in Bundle options);
+    void updateCredentials(in IAccountManagerResponse response, in Account account,
+        String authTokenType, boolean expectActivityLaunch, in Bundle options);
+    void editProperties(in IAccountManagerResponse response, String accountType,
+        boolean expectActivityLaunch);
+    void confirmCredentials(in IAccountManagerResponse response, in Account account,
+        boolean expectActivityLaunch);
+    void getAccountsByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
+        in String[] features);
+
+    /*
+     * @deprecated
+     */
+    void confirmPassword(in IAccountManagerResponse response, in Account account,
+        String password);
+}
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/IAccountManagerResponse.aidl
similarity index 60%
copy from core/java/android/accounts/AccountMonitorListener.java
copy to core/java/android/accounts/IAccountManagerResponse.aidl
index d0bd9a9..ca1203d 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/IAccountManagerResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -15,15 +15,13 @@
  */
 
 package android.accounts;
+import android.os.Bundle;
 
 /**
- * An interface that contains the callback used by the AccountMonitor
+ * The interface used to return responses for asynchronous calls to the {@link IAccountManager}
+ * @hide
  */
-public interface AccountMonitorListener {
-    /**
-     * This invoked when the AccountMonitor starts up and whenever the account
-     * set changes.
-     * @param currentAccounts the current accounts
-     */
-    void onAccountsUpdated(String[] currentAccounts);
+oneway interface IAccountManagerResponse {
+    void onResult(in Bundle value);
+    void onError(int errorCode, String errorMessage);
 }
diff --git a/core/java/android/accounts/IAccountsService.aidl b/core/java/android/accounts/IAccountsService.aidl
deleted file mode 100644
index dda513c..0000000
--- a/core/java/android/accounts/IAccountsService.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-/**
- * Central application service that allows querying the list of accounts.
- */
-interface IAccountsService {
-    /**
-     * Gets the list of Accounts the user has previously logged
-     * in to.  Accounts are of the form "username@domain".
-     * <p>
-     * This method will return an empty array if the device doesn't
-     * know about any accounts (yet).
-     *
-     * @return The accounts.  The array will be zero-length if the
-     *         AccountsService doesn't know about any accounts yet.
-     */
-    String[] getAccounts();
-
-    /**
-     * This is an interim solution for bypassing a forgotten gesture on the
-     * unlock screen (it is hidden, please make sure it stays this way!). This
-     * will be *removed* when the unlock screen design supports additional
-     * authenticators.
-     * <p>
-     * The user will be presented with username and password fields that are
-     * called as parameters to this method. If true is returned, the user is
-     * able to define a new gesture and get back into the system. If false, the
-     * user can try again.
-     * 
-     * @param username The username entered.
-     * @param password The password entered.
-     * @return Whether to allow the user to bypass the lock screen and define a
-     *         new gesture.
-     * @hide (The package is already hidden, but just in case someone
-     *       unhides that, this should not be revealed.)
-     */
-    boolean shouldUnlock(String username, String password);
-}
diff --git a/core/java/android/accounts/NetworkErrorException.java b/core/java/android/accounts/NetworkErrorException.java
new file mode 100644
index 0000000..f855cc8
--- /dev/null
+++ b/core/java/android/accounts/NetworkErrorException.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+public class NetworkErrorException extends Exception {
+    public NetworkErrorException() {
+        super();
+    }
+    public NetworkErrorException(String message) {
+        super(message);
+    }
+    public NetworkErrorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+    public NetworkErrorException(Throwable cause) {
+        super(cause);
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/OnAccountsUpdatedListener.java
similarity index 85%
rename from core/java/android/accounts/AccountMonitorListener.java
rename to core/java/android/accounts/OnAccountsUpdatedListener.java
index d0bd9a9..bd249d0 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/OnAccountsUpdatedListener.java
@@ -19,11 +19,11 @@
 /**
  * An interface that contains the callback used by the AccountMonitor
  */
-public interface AccountMonitorListener {
+public interface OnAccountsUpdatedListener {
     /**
      * This invoked when the AccountMonitor starts up and whenever the account
      * set changes.
-     * @param currentAccounts the current accounts
+     * @param accounts the current accounts
      */
-    void onAccountsUpdated(String[] currentAccounts);
+    void onAccountsUpdated(Account[] accounts);
 }
diff --git a/core/java/android/accounts/OperationCanceledException.java b/core/java/android/accounts/OperationCanceledException.java
new file mode 100644
index 0000000..2f2c164
--- /dev/null
+++ b/core/java/android/accounts/OperationCanceledException.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+public class OperationCanceledException extends Exception {
+    public OperationCanceledException() {
+        super();
+    }
+    public OperationCanceledException(String message) {
+        super(message);
+    }
+    public OperationCanceledException(String message, Throwable cause) {
+        super(message, cause);
+    }
+    public OperationCanceledException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/core/java/android/accounts/package.html b/core/java/android/accounts/package.html
deleted file mode 100755
index c9f96a6..0000000
--- a/core/java/android/accounts/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index a1f5a58..72d9e3d 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -88,6 +88,8 @@
 import android.view.LayoutInflater;
 import android.view.WindowManagerImpl;
 import android.view.inputmethod.InputMethodManager;
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
 
 import com.android.internal.policy.PolicyManager;
 
@@ -150,6 +152,7 @@
     private final static boolean DEBUG_ICONS = false;
 
     private static final Object sSync = new Object();
+    private static AccountManager sAccountManager;
     private static AlarmManager sAlarmManager;
     private static PowerManager sPowerManager;
     private static ConnectivityManager sConnectivityManager;
@@ -894,6 +897,8 @@
             return getActivityManager();
         } else if (ALARM_SERVICE.equals(name)) {
             return getAlarmManager();
+        } else if (ACCOUNT_SERVICE.equals(name)) {
+            return getAccountManager();
         } else if (POWER_SERVICE.equals(name)) {
             return getPowerManager();
         } else if (CONNECTIVITY_SERVICE.equals(name)) {
@@ -934,6 +939,17 @@
         return null;
     }
 
+    private AccountManager getAccountManager() {
+        synchronized (sSync) {
+            if (sAccountManager == null) {
+                IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+                IAccountManager service = IAccountManager.Stub.asInterface(b);
+                sAccountManager = new AccountManager(this, service);
+            }
+        }
+        return sAccountManager;
+    }
+
     private ActivityManager getActivityManager() {
         synchronized (mSync) {
             if (mActivityManager == null) {
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index ce6501c..edef332 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -4,8 +4,9 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.Cursor;
 import android.net.Uri;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.provider.SyncConstValue;
 import android.util.Config;
 import android.util.Log;
@@ -14,10 +15,11 @@
 
 import java.util.Collections;
 import java.util.Map;
-import java.util.HashMap;
 import java.util.Vector;
 import java.util.ArrayList;
 
+import com.google.android.collect.Maps;
+
 /**
  * A specialization of the ContentProvider that centralizes functionality
  * used by ContentProviders that are syncable. It also wraps calls to the ContentProvider
@@ -32,21 +34,22 @@
     private final String mDatabaseName;
     private final int mDatabaseVersion;
     private final Uri mContentUri;
-    private AccountMonitor mAccountMonitor;
 
     /** the account set in the last call to onSyncStart() */
-    private String mSyncingAccount;
+    private Account mSyncingAccount;
 
     private SyncStateContentProviderHelper mSyncState = null;
 
-    private static final String[] sAccountProjection = new String[] {SyncConstValue._SYNC_ACCOUNT};
+    private static final String[] sAccountProjection =
+            new String[] {SyncConstValue._SYNC_ACCOUNT, SyncConstValue._SYNC_ACCOUNT_TYPE};
 
     private boolean mIsTemporary;
 
     private AbstractTableMerger mCurrentMerger = null;
     private boolean mIsMergeCancelled = false;
 
-    private static final String SYNC_ACCOUNT_WHERE_CLAUSE = SyncConstValue._SYNC_ACCOUNT + "=?";
+    private static final String SYNC_ACCOUNT_WHERE_CLAUSE =
+            SyncConstValue._SYNC_ACCOUNT + "=? AND " + SyncConstValue._SYNC_ACCOUNT_TYPE + "=?";
 
     protected boolean isTemporary() {
         return mIsTemporary;
@@ -147,21 +150,23 @@
     @Override
     public boolean onCreate() {
         if (isTemporary()) throw new IllegalStateException("onCreate() called for temp provider");
-        mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(), mDatabaseName);
+        mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(),
+                mDatabaseName);
         mSyncState = new SyncStateContentProviderHelper(mOpenHelper);
-
-        AccountMonitorListener listener = new AccountMonitorListener() {
-            public void onAccountsUpdated(String[] accounts) {
-                // Some providers override onAccountsChanged(); give them a database to work with.
-                mDb = mOpenHelper.getWritableDatabase();
-                onAccountsChanged(accounts);
-                TempProviderSyncAdapter syncAdapter = (TempProviderSyncAdapter)getSyncAdapter();
-                if (syncAdapter != null) {
-                    syncAdapter.onAccountsChanged(accounts);
-                }
-            }
-        };
-        mAccountMonitor = new AccountMonitor(getContext(), listener);
+        AccountManager.get(getContext()).addOnAccountsUpdatedListener(
+                new OnAccountsUpdatedListener() {
+                    public void onAccountsUpdated(Account[] accounts) {
+                        // Some providers override onAccountsChanged(); give them a database to
+                        // work with.
+                        mDb = mOpenHelper.getWritableDatabase();
+                        onAccountsChanged(accounts);
+                        TempProviderSyncAdapter syncAdapter =
+                                (TempProviderSyncAdapter)getSyncAdapter();
+                        if (syncAdapter != null) {
+                            syncAdapter.onAccountsChanged(accounts);
+                        }
+                    }
+                }, null /* handler */, true /* updateImmediately */);
 
         return true;
     }
@@ -365,8 +370,8 @@
      * @param context the sync context for the operation
      * @param account
      */
-    public void onSyncStart(SyncContext context, String account) {
-        if (TextUtils.isEmpty(account)) {
+    public void onSyncStart(SyncContext context, Account account) {
+        if (account == null) {
             throw new IllegalArgumentException("you passed in an empty account");
         }
         mSyncingAccount = account;
@@ -385,7 +390,7 @@
      * The account of the most recent call to onSyncStart()
      * @return the account
      */
-    public String getSyncingAccount() {
+    public Account getSyncingAccount() {
         return mSyncingAccount;
     }
 
@@ -496,12 +501,11 @@
      * Make sure that there are no entries for accounts that no longer exist
      * @param accountsArray the array of currently-existing accounts
      */
-    protected void onAccountsChanged(String[] accountsArray) {
-        Map<String, Boolean> accounts = new HashMap<String, Boolean>();
-        for (String account : accountsArray) {
+    protected void onAccountsChanged(Account[] accountsArray) {
+        Map<Account, Boolean> accounts = Maps.newHashMap();
+        for (Account account : accountsArray) {
             accounts.put(account, false);
         }
-        accounts.put(SyncConstValue.NON_SYNCABLE_ACCOUNT, false);
 
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Map<String, String> tableMap = db.getSyncedTables();
@@ -513,8 +517,7 @@
         try {
             mSyncState.onAccountsChanged(accountsArray);
             for (String table : tables) {
-                deleteRowsForRemovedAccounts(accounts, table,
-                        SyncConstValue._SYNC_ACCOUNT);
+                deleteRowsForRemovedAccounts(accounts, table);
             }
             db.setTransactionSuccessful();
         } finally {
@@ -529,23 +532,23 @@
      *
      * @param accounts a map of existing accounts
      * @param table the table to delete from
-     * @param accountColumnName the name of the column that is expected
-     * to hold the account.
      */
-    protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
-            String table, String accountColumnName) {
+    protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Cursor c = db.query(table, sAccountProjection, null, null,
-                accountColumnName, null, null);
+                "_sync_account, _sync_account_type", null, null);
         try {
             while (c.moveToNext()) {
-                String account = c.getString(0);
-                if (TextUtils.isEmpty(account)) {
+                String accountName = c.getString(0);
+                String accountType = c.getString(1);
+                if (TextUtils.isEmpty(accountName)) {
                     continue;
                 }
+                Account account = new Account(accountName, accountType);
                 if (!accounts.containsKey(account)) {
                     int numDeleted;
-                    numDeleted = db.delete(table, accountColumnName + "=?", new String[]{account});
+                    numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
+                            new String[]{account.mName, account.mType});
                     if (Config.LOGV) {
                         Log.v(TAG, "deleted " + numDeleted
                                 + " records from table " + table
@@ -562,7 +565,7 @@
      * Called when the sync system determines that this provider should no longer
      * contain records for the specified account.
      */
-    public void wipeAccount(String account) {
+    public void wipeAccount(Account account) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Map<String, String> tableMap = db.getSyncedTables();
         ArrayList<String> tables = new ArrayList<String>();
@@ -577,7 +580,8 @@
 
             // remove the data in the synced tables
             for (String table : tables) {
-                db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE, new String[]{account});
+                db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
+                        new String[]{account.mName, account.mType});
             }
             db.setTransactionSuccessful();
         } finally {
@@ -588,14 +592,14 @@
     /**
      * Retrieves the SyncData bytes for the given account. The byte array returned may be null.
      */
-    public byte[] readSyncDataBytes(String account) {
+    public byte[] readSyncDataBytes(Account account) {
         return mSyncState.readSyncDataBytes(mOpenHelper.getReadableDatabase(), account);
     }
 
     /**
      * Sets the SyncData bytes for the given account. The byte array may be null.
      */
-    public void writeSyncDataBytes(String account, byte[] data) {
+    public void writeSyncDataBytes(Account account, byte[] data) {
         mSyncState.writeSyncDataBytes(mOpenHelper.getWritableDatabase(), account, data);
     }
 }
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 700f1d8..8c9955a2 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -25,6 +25,7 @@
 import static android.provider.SyncConstValue.*;
 import android.text.TextUtils;
 import android.util.Log;
+import android.accounts.Account;
 
 /**
  * @hide
@@ -55,14 +56,16 @@
 
     private volatile boolean mIsMergeCancelled;
 
-    private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and " + _SYNC_ACCOUNT + "=?";
+    private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and "
+            + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
 
     private static final String SELECT_BY_SYNC_ID_AND_ACCOUNT =
-            _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=?";
+            _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
     private static final String SELECT_BY_ID = BaseColumns._ID +"=?";
 
     private static final String SELECT_UNSYNCED = ""
-            + _SYNC_DIRTY + " > 0 and (" + _SYNC_ACCOUNT + "=? or " + _SYNC_ACCOUNT + " is null)";
+            + _SYNC_DIRTY + " > 0 and ((" + _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=?) "
+            + "or " + _SYNC_ACCOUNT + " is null)";
 
     public AbstractTableMerger(SQLiteDatabase database,
             String table, Uri tableURL, String deletedTable,
@@ -132,7 +135,7 @@
      * construct a temporary instance to hold them.
      */
     public void merge(final SyncContext context,
-            final String account,
+            final Account account,
             final SyncableContentProvider serverDiffs,
             TempProviderSyncResult result,
             SyncResult syncResult, SyncableContentProvider temporaryInstanceFactory) {
@@ -155,7 +158,7 @@
      * @hide this is public for testing purposes only
      */
     public void mergeServerDiffs(SyncContext context,
-            String account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
+            Account account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
         boolean diffsArePartial = serverDiffs.getContainsDiffs();
         // mark the current rows so that we can distinguish these from new
         // inserts that occur during the merge
@@ -164,333 +167,331 @@
             mDb.update(mDeletedTable, mSyncMarkValues, null, null);
         }
 
-        // load the local database entries, so we can merge them with the server
-        final String[] accountSelectionArgs = new String[]{account};
-        Cursor localCursor = mDb.query(mTable, syncDirtyProjection,
-                SELECT_MARKED, accountSelectionArgs, null, null,
-                mTable + "." + _SYNC_ID);
-        Cursor deletedCursor;
-        if (mDeletedTable != null) {
-            deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+        Cursor localCursor = null;
+        Cursor deletedCursor = null;
+        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};
+            localCursor = mDb.query(mTable, syncDirtyProjection,
                     SELECT_MARKED, accountSelectionArgs, null, null,
-                    mDeletedTable + "." + _SYNC_ID);
-        } else {
-            deletedCursor =
-                    mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
-        }
-
-        // Apply updates and insertions from the server
-        Cursor diffsCursor = serverDiffs.query(mTableURL,
-                null, null, null, mTable + "." + _SYNC_ID);
-        int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
-        int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
-        int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
-        int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
-        int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
-
-        String lastSyncId = null;
-        int diffsCount = 0;
-        int localCount = 0;
-        localCursor.moveToFirst();
-        deletedCursor.moveToFirst();
-        while (diffsCursor.moveToNext()) {
-            if (mIsMergeCancelled) {
-                localCursor.close();
-                deletedCursor.close();
-                diffsCursor.close();
-                return;
-            }
-            mDb.yieldIfContended();
-            String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
-            String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
-            long localRowId = 0;
-            String localSyncVersion = null;
-
-            diffsCount++;
-            context.setStatusText("Processing " + diffsCount + "/"
-                    + diffsCursor.getCount());
-            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
-                    diffsCount + ", " + serverSyncId);
-
-            if (TRACE) {
-                if (diffsCount == 10) {
-                    Debug.startMethodTracing("atmtrace");
-                }
-                if (diffsCount == 20) {
-                    Debug.stopMethodTracing();
-                }
+                    mTable + "." + _SYNC_ID);
+            if (mDeletedTable != null) {
+                deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+                        SELECT_MARKED, accountSelectionArgs, null, null,
+                        mDeletedTable + "." + _SYNC_ID);
+            } else {
+                deletedCursor =
+                        mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
             }
 
-            boolean conflict = false;
-            boolean update = false;
-            boolean insert = false;
+            // Apply updates and insertions from the server
+            diffsCursor = serverDiffs.query(mTableURL,
+                    null, null, null, mTable + "." + _SYNC_ID);
+            int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
+            int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+            int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
+            int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+            int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
+
+            String lastSyncId = null;
+            int diffsCount = 0;
+            int localCount = 0;
+            localCursor.moveToFirst();
+            deletedCursor.moveToFirst();
+            while (diffsCursor.moveToNext()) {
+                if (mIsMergeCancelled) {
+                    return;
+                }
+                mDb.yieldIfContended();
+                String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
+                String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
+                long localRowId = 0;
+                String localSyncVersion = null;
+
+                diffsCount++;
+                context.setStatusText("Processing " + diffsCount + "/"
+                        + diffsCursor.getCount());
+                if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
+                        diffsCount + ", " + serverSyncId);
+
+                if (TRACE) {
+                    if (diffsCount == 10) {
+                        Debug.startMethodTracing("atmtrace");
+                    }
+                    if (diffsCount == 20) {
+                        Debug.stopMethodTracing();
+                    }
+                }
+
+                boolean conflict = false;
+                boolean update = false;
+                boolean insert = false;
+
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "found event with serverSyncID " + serverSyncId);
+                }
+                if (TextUtils.isEmpty(serverSyncId)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.e(TAG, "server entry doesn't have a serverSyncID");
+                    }
+                    continue;
+                }
+
+                // It is possible that the sync adapter wrote the same record multiple times,
+                // e.g. if the same record came via multiple feeds. If this happens just ignore
+                // the duplicate records.
+                if (serverSyncId.equals(lastSyncId)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
+                    }
+                    continue;
+                }
+                lastSyncId = serverSyncId;
+
+                String localSyncID = null;
+                boolean localSyncDirty = false;
+
+                while (!localCursor.isAfterLast()) {
+                    if (mIsMergeCancelled) {
+                        return;
+                    }
+                    localCount++;
+                    localSyncID = localCursor.getString(2);
+
+                    // If the local record doesn't have a _sync_id then
+                    // it is new. Ignore it for now, we will send an insert
+                    // the the server later.
+                    if (TextUtils.isEmpty(localSyncID)) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "local record " +
+                                    localCursor.getLong(1) +
+                                    " has no _sync_id, ignoring");
+                        }
+                        localCursor.moveToNext();
+                        localSyncID = null;
+                        continue;
+                    }
+
+                    int comp = serverSyncId.compareTo(localSyncID);
+
+                    // the local DB has a record that the server doesn't have
+                    if (comp > 0) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "local record " +
+                                    localCursor.getLong(1) +
+                                    " has _sync_id " + localSyncID +
+                                    " that is < server _sync_id " + serverSyncId);
+                        }
+                        if (diffsArePartial) {
+                            localCursor.moveToNext();
+                        } else {
+                            deleteRow(localCursor);
+                            if (mDeletedTable != null) {
+                                mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
+                            }
+                            syncResult.stats.numDeletes++;
+                            mDb.yieldIfContended();
+                        }
+                        localSyncID = null;
+                        continue;
+                    }
+
+                    // the server has a record that the local DB doesn't have
+                    if (comp < 0) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "local record " +
+                                    localCursor.getLong(1) +
+                                    " has _sync_id " + localSyncID +
+                                    " that is > server _sync_id " + serverSyncId);
+                        }
+                        localSyncID = null;
+                    }
+
+                    // the server and the local DB both have this record
+                    if (comp == 0) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "local record " +
+                                    localCursor.getLong(1) +
+                                    " has _sync_id " + localSyncID +
+                                    " that matches the server _sync_id");
+                        }
+                        localSyncDirty = localCursor.getInt(0) != 0;
+                        localRowId = localCursor.getLong(1);
+                        localSyncVersion = localCursor.getString(3);
+                        localCursor.moveToNext();
+                    }
+
+                    break;
+                }
+
+                // If this record is in the deleted table then update the server version
+                // in the deleted table, if necessary, and then ignore it here.
+                // We will send a deletion indication to the server down a
+                // little further.
+                if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
+                    }
+                    final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
+                    if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
+                                    + serverSyncVersion);
+                        }
+                        ContentValues values = new ContentValues();
+                        values.put(_SYNC_VERSION, serverSyncVersion);
+                        mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
+                    }
+                    continue;
+                }
+
+                // If the _sync_local_id is present in the diffsCursor
+                // then this record corresponds to a local record that was just
+                // inserted into the server and the _sync_local_id is the row id
+                // of the local record. Set these fields so that the next check
+                // treats this record as an update, which will allow the
+                // merger to update the record with the server's sync id
+                if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
+                    localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "the remote record with sync id " + serverSyncId
+                                + " has a local sync id, " + localRowId);
+                    }
+                    localSyncID = serverSyncId;
+                    localSyncDirty = false;
+                    localSyncVersion = null;
+                }
+
+                if (!TextUtils.isEmpty(localSyncID)) {
+                    // An existing server item has changed
+                    boolean recordChanged = (localSyncVersion == null) ||
+                            !serverSyncVersion.equals(localSyncVersion);
+                    if (recordChanged) {
+                        if (localSyncDirty) {
+                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                                Log.v(TAG, "remote record " + serverSyncId
+                                        + " conflicts with local _sync_id " + localSyncID
+                                        + ", local _id " + localRowId);
+                            }
+                            conflict = true;
+                        } else {
+                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                                 Log.v(TAG,
+                                         "remote record " +
+                                                 serverSyncId +
+                                         " updates local _sync_id " +
+                                         localSyncID + ", local _id " +
+                                         localRowId);
+                             }
+                             update = true;
+                        }
+                    }
+                } else {
+                    // the local db doesn't know about this record so add it
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
+                    }
+                    insert = true;
+                }
+
+                if (update) {
+                    updateRow(localRowId, serverDiffs, diffsCursor);
+                    syncResult.stats.numUpdates++;
+                } else if (conflict) {
+                    resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
+                    syncResult.stats.numUpdates++;
+                } else if (insert) {
+                    insertRow(serverDiffs, diffsCursor);
+                    syncResult.stats.numInserts++;
+                }
+            }
 
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "found event with serverSyncID " + serverSyncId);
-            }
-            if (TextUtils.isEmpty(serverSyncId)) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.e(TAG, "server entry doesn't have a serverSyncID");
-                }
-                continue;
+                Log.v(TAG, "processed " + diffsCount + " server entries");
             }
 
-            // It is possible that the sync adapter wrote the same record multiple times,
-            // e.g. if the same record came via multiple feeds. If this happens just ignore
-            // the duplicate records.
-            if (serverSyncId.equals(lastSyncId)) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
-                }
-                continue;
-            }
-            lastSyncId = serverSyncId;
-
-            String localSyncID = null;
-            boolean localSyncDirty = false;
-
-            while (!localCursor.isAfterLast()) {
-                if (mIsMergeCancelled) {
-                    localCursor.deactivate();
-                    deletedCursor.deactivate();
-                    diffsCursor.deactivate();
-                    return;
-                }
-                localCount++;
-                localSyncID = localCursor.getString(2);
-
-                // If the local record doesn't have a _sync_id then
-                // it is new. Ignore it for now, we will send an insert
-                // the the server later.
-                if (TextUtils.isEmpty(localSyncID)) {
+            // If tombstones aren't in use delete any remaining local rows that
+            // don't have corresponding server rows. Keep the rows that don't
+            // have a sync id since those were created locally and haven't been
+            // synced to the server yet.
+            if (!diffsArePartial) {
+                while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
+                    if (mIsMergeCancelled) {
+                        return;
+                    }
+                    localCount++;
+                    final String localSyncId = localCursor.getString(2);
                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "local record " +
-                                localCursor.getLong(1) +
-                                " has no _sync_id, ignoring");
+                        Log.v(TAG,
+                                "deleting local record " +
+                                        localCursor.getLong(1) +
+                                        " _sync_id " + localSyncId);
                     }
-                    localCursor.moveToNext();
-                    localSyncID = null;
-                    continue;
+                    deleteRow(localCursor);
+                    if (mDeletedTable != null) {
+                        mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
+                    }
+                    syncResult.stats.numDeletes++;
+                    mDb.yieldIfContended();
                 }
-
-                int comp = serverSyncId.compareTo(localSyncID);
-
-                // the local DB has a record that the server doesn't have
-                if (comp > 0) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "local record " +
-                                localCursor.getLong(1) +
-                                " has _sync_id " + localSyncID +
-                                " that is < server _sync_id " + serverSyncId);
-                    }
-                    if (diffsArePartial) {
-                        localCursor.moveToNext();
-                    } else {
-                        deleteRow(localCursor);
-                        if (mDeletedTable != null) {
-                            mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
-                        }
-                        syncResult.stats.numDeletes++;
-                        mDb.yieldIfContended();
-                    }
-                    localSyncID = null;
-                    continue;
-                }
-
-                // the server has a record that the local DB doesn't have
-                if (comp < 0) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "local record " +
-                                localCursor.getLong(1) +
-                                " has _sync_id " + localSyncID +
-                                " that is > server _sync_id " + serverSyncId);
-                    }
-                    localSyncID = null;
-                }
-
-                // the server and the local DB both have this record
-                if (comp == 0) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "local record " +
-                                localCursor.getLong(1) +
-                                " has _sync_id " + localSyncID +
-                                " that matches the server _sync_id");
-                    }
-                    localSyncDirty = localCursor.getInt(0) != 0;
-                    localRowId = localCursor.getLong(1);
-                    localSyncVersion = localCursor.getString(3);
-                    localCursor.moveToNext();
-                }
-
-                break;
             }
-
-            // If this record is in the deleted table then update the server version
-            // in the deleted table, if necessary, and then ignore it here.
-            // We will send a deletion indication to the server down a
-            // little further.
-            if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
-                }
-                final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
-                if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
-                                + serverSyncVersion);
-                    }
-                    ContentValues values = new ContentValues();
-                    values.put(_SYNC_VERSION, serverSyncVersion);
-                    mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
-                }
-                continue;
-            }
-
-            // If the _sync_local_id is present in the diffsCursor
-            // then this record corresponds to a local record that was just
-            // inserted into the server and the _sync_local_id is the row id
-            // of the local record. Set these fields so that the next check
-            // treats this record as an update, which will allow the
-            // merger to update the record with the server's sync id
-            if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
-                localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "the remote record with sync id " + serverSyncId
-                            + " has a local sync id, " + localRowId);
-                }
-                localSyncID = serverSyncId;
-                localSyncDirty = false;
-                localSyncVersion = null;
-            }
-
-            if (!TextUtils.isEmpty(localSyncID)) {
-                // An existing server item has changed
-                boolean recordChanged = (localSyncVersion == null) ||
-                        !serverSyncVersion.equals(localSyncVersion);
-                if (recordChanged) {
-                    if (localSyncDirty) {
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                            Log.v(TAG, "remote record " + serverSyncId
-                                    + " conflicts with local _sync_id " + localSyncID
-                                    + ", local _id " + localRowId);
-                        }
-                        conflict = true;
-                    } else {
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                             Log.v(TAG,
-                                     "remote record " +
-                                             serverSyncId +
-                                     " updates local _sync_id " +
-                                     localSyncID + ", local _id " +
-                                     localRowId);
-                         }
-                         update = true;
-                    }
-                }
-            } else {
-                // the local db doesn't know about this record so add it
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
-                }
-                insert = true;
-            }
-
-            if (update) {
-                updateRow(localRowId, serverDiffs, diffsCursor);
-                syncResult.stats.numUpdates++;
-            } else if (conflict) {
-                resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
-                syncResult.stats.numUpdates++;
-            } else if (insert) {
-                insertRow(serverDiffs, diffsCursor);
-                syncResult.stats.numInserts++;
-            }
+            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
+                    " local entries");
+        } finally {
+            if (diffsCursor != null) diffsCursor.close();
+            if (localCursor != null) localCursor.close();
+            if (deletedCursor != null) deletedCursor.close();
         }
 
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "processed " + diffsCount + " server entries");
-        }
-
-        // If tombstones aren't in use delete any remaining local rows that
-        // don't have corresponding server rows. Keep the rows that don't
-        // have a sync id since those were created locally and haven't been
-        // synced to the server yet.
-        if (!diffsArePartial) {
-            while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
-                if (mIsMergeCancelled) {
-                    localCursor.deactivate();
-                    deletedCursor.deactivate();
-                    diffsCursor.deactivate();
-                    return;
-                }
-                localCount++;
-                final String localSyncId = localCursor.getString(2);
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG,
-                            "deleting local record " +
-                                    localCursor.getLong(1) +
-                                    " _sync_id " + localSyncId);
-                }
-                deleteRow(localCursor);
-                if (mDeletedTable != null) {
-                    mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
-                }
-                syncResult.stats.numDeletes++;
-                mDb.yieldIfContended();
-            }
-        }
-
-        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
-                " local entries");
-        diffsCursor.deactivate();
-        localCursor.deactivate();
-        deletedCursor.deactivate();
 
         if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "applying deletions from the server");
 
         // Apply deletions from the server
         if (mDeletedTableURL != null) {
             diffsCursor = serverDiffs.query(mDeletedTableURL, null, null, null, null);
-
-            while (diffsCursor.moveToNext()) {
-                if (mIsMergeCancelled) {
-                    diffsCursor.deactivate();
-                    return;
+            try {
+                while (diffsCursor.moveToNext()) {
+                    if (mIsMergeCancelled) {
+                        return;
+                    }
+                    // delete all rows that match each element in the diffsCursor
+                    fullyDeleteMatchingRows(diffsCursor, account, syncResult);
+                    mDb.yieldIfContended();
                 }
-                // delete all rows that match each element in the diffsCursor
-                fullyDeleteMatchingRows(diffsCursor, account, syncResult);
-                mDb.yieldIfContended();
+            } finally {
+                diffsCursor.close();
             }
-            diffsCursor.deactivate();
         }
     }
 
-    private void fullyDeleteMatchingRows(Cursor diffsCursor, String account,
+    private void fullyDeleteMatchingRows(Cursor diffsCursor, Account account,
             SyncResult syncResult) {
         int serverSyncIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
         final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn);
 
         // delete the rows explicitly so that the delete operation can be overridden
-        final Cursor c;
         final String[] selectionArgs;
-        if (deleteBySyncId) {
-            selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
-            c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
-                    selectionArgs, null, null, null);
-        } else {
-            int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
-            selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
-            c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
-                    null, null, null);
-        }
+        Cursor c = null;
         try {
+            if (deleteBySyncId) {
+                selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
+                        account.mName, account.mType};
+                c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
+                        selectionArgs, null, null, null);
+            } else {
+                int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
+                selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
+                c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
+                        null, null, null);
+            }
             c.moveToFirst();
             while (!c.isAfterLast()) {
                 deleteRow(c); // advances the cursor
                 syncResult.stats.numDeletes++;
             }
         } finally {
-            c.deactivate();
+          if (c != null) c.close();
         }
         if (deleteBySyncId && mDeletedTable != null) {
             mDb.delete(mDeletedTable, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs);
@@ -508,43 +509,46 @@
      * Finds local changes, placing the results in the given result object.
      * @param temporaryInstanceFactory As an optimization for the case
      * where there are no client-side diffs, mergeResult may initially
-     * have no {@link android.content.TempProviderSyncResult#tempContentProvider}.  If this is
+     * have no {@link TempProviderSyncResult#tempContentProvider}.  If this is
      * the first in the sequence of AbstractTableMergers to find
      * client-side diffs, it will use the given ContentProvider to
      * create a temporary instance and store its {@link
-     * ContentProvider} in the mergeResult.
+     * android.content.ContentProvider} in the mergeResult.
      * @param account
      * @param syncResult
      */
     private void findLocalChanges(TempProviderSyncResult mergeResult,
-            SyncableContentProvider temporaryInstanceFactory, String account,
+            SyncableContentProvider temporaryInstanceFactory, Account account,
             SyncResult syncResult) {
         SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
         if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
 
-        final String[] accountSelectionArgs = new String[]{account};
+        final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
 
         // Generate the client updates and insertions
         // Create a cursor for dirty records
+        long numInsertsOrUpdates = 0;
         Cursor localChangesCursor = mDb.query(mTable, null, SELECT_UNSYNCED, accountSelectionArgs,
                 null, null, null);
-        long numInsertsOrUpdates = localChangesCursor.getCount();
-        while (localChangesCursor.moveToNext()) {
-            if (mIsMergeCancelled) {
-                localChangesCursor.close();
-                return;
+        try {
+            numInsertsOrUpdates = localChangesCursor.getCount();
+            while (localChangesCursor.moveToNext()) {
+                if (mIsMergeCancelled) {
+                    return;
+                }
+                if (clientDiffs == null) {
+                    clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+                }
+                mValues.clear();
+                cursorRowToContentValues(localChangesCursor, mValues);
+                mValues.remove("_id");
+                DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
+                        _SYNC_LOCAL_ID);
+                clientDiffs.insert(mTableURL, mValues);
             }
-            if (clientDiffs == null) {
-                clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
-            }
-            mValues.clear();
-            cursorRowToContentValues(localChangesCursor, mValues);
-            mValues.remove("_id");
-            DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
-                    _SYNC_LOCAL_ID);
-            clientDiffs.insert(mTableURL, mValues);
+        } finally {
+          localChangesCursor.close();
         }
-        localChangesCursor.close();
 
         // Generate the client deletions
         if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client deletions");
@@ -553,23 +557,25 @@
         if (mDeletedTable != null) {
             Cursor deletedCursor = mDb.query(mDeletedTable,
                     syncIdAndVersionProjection,
-                    _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
+                    _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=? AND "
+                            + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
                     null, null, mDeletedTable + "." + _SYNC_ID);
-
-            numDeletedEntries = deletedCursor.getCount();
-            while (deletedCursor.moveToNext()) {
-                if (mIsMergeCancelled) {
-                    deletedCursor.close();
-                    return;
+            try {
+                numDeletedEntries = deletedCursor.getCount();
+                while (deletedCursor.moveToNext()) {
+                    if (mIsMergeCancelled) {
+                        return;
+                    }
+                    if (clientDiffs == null) {
+                        clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+                    }
+                    mValues.clear();
+                    DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
+                    clientDiffs.insert(mDeletedTableURL, mValues);
                 }
-                if (clientDiffs == null) {
-                    clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
-                }
-                mValues.clear();
-                DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
-                clientDiffs.insert(mDeletedTableURL, mValues);
+            } finally {
+                deletedCursor.close();
             }
-            deletedCursor.close();
         }
 
         if (clientDiffs != null) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a71d57..6577236 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -28,6 +28,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.accounts.Account;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -691,6 +692,7 @@
      * <li>Float</li>
      * <li>Double</li>
      * <li>String</li>
+     * <li>Account</li>
      * <li>null</li>
      * </ul>
      * @param extras the Bundle to check
@@ -706,6 +708,7 @@
                 if (value instanceof Float) continue;
                 if (value instanceof Double) continue;
                 if (value instanceof String) continue;
+                if (value instanceof Account) continue;
                 throw new IllegalArgumentException("unexpected value type: "
                         + value.getClass().getName());
             }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a301449..e8daa6e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1108,6 +1108,16 @@
     public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.accounts.AccountManager} for receiving intents at a
+     * time of your choosing.
+     * TODO STOPSHIP perform a final review of the the account apis before shipping
+     *
+     * @see #getSystemService
+     * @see android.accounts.AccountManager
+     */
+    public static final String ACCOUNT_SERVICE = "account";
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.app.ActivityManager} for interacting with the global
      * system state.
      *
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 671188c..d228605 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.accounts.Account;
 import android.os.Bundle;
 import android.content.ISyncContext;
 
@@ -33,7 +34,7 @@
      * @param account the account that should be synced
      * @param extras SyncAdapter-specific parameters
      */
-    void startSync(ISyncContext syncContext, String account, in Bundle extras);
+    void startSync(ISyncContext syncContext, in Account account, in Bundle extras);
 
     /**
      * Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b3e81d7..ebdd588 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1259,7 +1259,7 @@
      * that wait until power is available to trigger.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
+    public static final String ACTION_POWER_CONNECTED = "android.intent.action.POWER_CONNECTED";
     /**
      * Broadcast Action:  External power has been removed from the device.
      * This is intended for applications that wish to register specifically to this notification.
@@ -1268,7 +1268,8 @@
      * that wait until power is available to trigger. 
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";    
+    public static final String ACTION_POWER_DISCONNECTED =
+            "android.intent.action.POWER_DISCONNECTED";    
     /**
      * Broadcast Action:  Indicates low memory condition on the device
      */
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index e5c5dc8..365f269 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -366,6 +366,7 @@
         throws MalformedMimeTypeException {
         mPriority = 0;
         mActions = new ArrayList<String>();
+        addAction(action);
         addDataType(dataType);
     }
 
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 7826e50..3e91626 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -18,6 +18,7 @@
 
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.accounts.Account;
 
 /**
  * @hide
@@ -29,7 +30,7 @@
     public static final int LOG_SYNC_DETAILS = 2743;
 
     class Transport extends ISyncAdapter.Stub {
-        public void startSync(ISyncContext syncContext, String account,
+        public void startSync(ISyncContext syncContext, Account account,
                 Bundle extras) throws RemoteException {
             SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
         }
@@ -59,7 +60,7 @@
      * @param account the account that should be synced
      * @param extras SyncAdapter-specific parameters
      */
-    public abstract void startSync(SyncContext syncContext, String account, Bundle extras);
+    public abstract void startSync(SyncContext syncContext, Account account, Bundle extras);
 
     /**
      * Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 96470c3..4474c62 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -21,8 +21,9 @@
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -50,8 +51,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
 import android.provider.Sync;
 import android.provider.Settings;
 import android.provider.Sync.History;
@@ -84,7 +83,7 @@
 /**
  * @hide
  */
-class SyncManager {
+class SyncManager implements OnAccountsUpdatedListener {
     private static final String TAG = "SyncManager";
 
     // used during dumping of the Sync history
@@ -130,9 +129,7 @@
     private String mStatusText = "";
     private long mHeartbeatTime = 0;
 
-    private AccountMonitor mAccountMonitor;
-
-    private volatile String[] mAccounts = null;
+    private volatile Account[] mAccounts = null;
 
     volatile private PowerManager.WakeLock mSyncWakeLock;
     volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
@@ -181,6 +178,43 @@
                 }
             };
 
+    private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            if (!mFactoryTest) {
+                AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,
+                        mSyncHandler, true /* updateImmediately */);
+            }
+        }
+    };
+
+    public void onAccountsUpdated(Account[] accounts) {
+        final boolean hadAccountsAlready = mAccounts != null;
+        mAccounts = accounts;
+
+        // if a sync is in progress yet it is no longer in the accounts list,
+        // cancel it
+        ActiveSyncContext activeSyncContext = mActiveSyncContext;
+        if (activeSyncContext != null) {
+            if (!ArrayUtils.contains(accounts, activeSyncContext.mSyncOperation.account)) {
+                Log.d(TAG, "canceling sync since the account has been removed");
+                sendSyncFinishedOrCanceledMessage(activeSyncContext,
+                        null /* no result since this is a cancel */);
+            }
+        }
+
+        // we must do this since we don't bother scheduling alarms when
+        // the accounts are not set yet
+        sendCheckAlarmsMessage();
+
+        mSyncStorageEngine.doDatabaseCleanup(accounts);
+
+        if (hadAccountsAlready && accounts.length > 0) {
+            // request a sync so that if the password was changed we will
+            // retry any sync that failed when it was wrong
+            startSync(null /* all providers */, null /* no extras */);
+        }
+    }
+
     private BroadcastReceiver mConnectivityIntentReceiver =
             new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
@@ -241,7 +275,11 @@
 
     private static final String SYNCMANAGER_PREFS_FILENAME = "/data/system/syncmanager.prefs";
 
+    private final boolean mFactoryTest;
+
     public SyncManager(Context context, boolean factoryTest) {
+        mFactoryTest = factoryTest;
+
         // Initialize the SyncStorageEngine first, before registering observers
         // and creating threads and so on; it may fail if the disk is full.
         SyncStorageEngine.init(context);
@@ -265,6 +303,9 @@
         IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
         context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
 
+        intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+        context.registerReceiver(mBootCompletedReceiver, intentFilter);
+
         intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
         intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
         context.registerReceiver(mStorageIntentReceiver, intentFilter);
@@ -288,42 +329,6 @@
         mHandleAlarmWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 HANDLE_SYNC_ALARM_WAKE_LOCK);
         mHandleAlarmWakeLock.setReferenceCounted(false);
-
-        if (!factoryTest) {
-            AccountMonitorListener listener = new AccountMonitorListener() {
-                public void onAccountsUpdated(String[] accounts) {
-                    final boolean hadAccountsAlready = mAccounts != null;
-                    // copy the accounts into a new array and change mAccounts to point to it
-                    String[] newAccounts = new String[accounts.length];
-                    System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
-                    mAccounts = newAccounts;
-
-                    // if a sync is in progress yet it is no longer in the accounts list, cancel it
-                    ActiveSyncContext activeSyncContext = mActiveSyncContext;
-                    if (activeSyncContext != null) {
-                        if (!ArrayUtils.contains(newAccounts,
-                                activeSyncContext.mSyncOperation.account)) {
-                            Log.d(TAG, "canceling sync since the account has been removed");
-                            sendSyncFinishedOrCanceledMessage(activeSyncContext,
-                                    null /* no result since this is a cancel */);
-                        }
-                    }
-
-                    // we must do this since we don't bother scheduling alarms when
-                    // the accounts are not set yet
-                    sendCheckAlarmsMessage();
-
-                    mSyncStorageEngine.doDatabaseCleanup(accounts);
-
-                    if (hadAccountsAlready && mAccounts.length > 0) {
-                        // request a sync so that if the password was changed we will retry any sync
-                        // that failed when it was wrong
-                        startSync(null /* all providers */, null /* no extras */);
-                    }
-                }
-            };
-            mAccountMonitor = new AccountMonitor(context, listener);
-        }
     }
 
     private synchronized void initializeSyncPoll() {
@@ -474,7 +479,7 @@
         }
     }
 
-    public String getSyncingAccount() {
+    public Account getSyncingAccount() {
         ActiveSyncContext activeSyncContext = mActiveSyncContext;
         return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
     }
@@ -545,10 +550,10 @@
             delay = -1; // this means schedule at the front of the queue
         }
 
-        String[] accounts;
-        String accountFromExtras = extras.getString(ContentResolver.SYNC_EXTRAS_ACCOUNT);
-        if (!TextUtils.isEmpty(accountFromExtras)) {
-            accounts = new String[]{accountFromExtras};
+        Account[] accounts;
+        Account accountFromExtras = extras.getParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT);
+        if (accountFromExtras != null) {
+            accounts = new Account[]{accountFromExtras};
         } else {
             // if the accounts aren't configured yet then we can't support an account-less
             // sync request
@@ -593,7 +598,7 @@
         for (int i = 0; i < numProviders; i++) {
             if (!providers.get(i).isSyncable) continue;
             final String name = names.get(i);
-            for (String account : accounts) {
+            for (Account account : accounts) {
                 scheduleSyncOperation(new SyncOperation(account, source, name, extras, delay));
                 // TODO: remove this when Calendar supports multiple accounts. Until then
                 // pretend that only the first account exists when syncing calendar.
@@ -869,7 +874,7 @@
      * Value type that represents a sync operation.
      */
     static class SyncOperation implements Comparable {
-        final String account;
+        final Account account;
         int syncSource;
         String authority;
         Bundle extras;
@@ -878,7 +883,7 @@
         long delay;
         Long rowId = null;
 
-        SyncOperation(String account, int source, String authority, Bundle extras, long delay) {
+        SyncOperation(Account account, int source, String authority, Bundle extras, long delay) {
             this.account = account;
             this.syncSource = source;
             this.authority = authority;
@@ -1012,7 +1017,7 @@
         sb.append("data connected: ").append(mDataConnectionIsConnected).append("\n");
         sb.append("memory low: ").append(mStorageIsLow).append("\n");
 
-        final String[] accounts = mAccounts;
+        final Account[] accounts = mAccounts;
         sb.append("accounts: ");
         if (accounts != null) {
             sb.append(accounts.length);
@@ -1083,17 +1088,18 @@
             c.close();
         }
 
-        String currentAccount = null;
+        Account currentAccount = null;
         c = mSyncStorageEngine.query(Sync.Status.CONTENT_URI,
-                STATUS_PROJECTION, null, null, "account, authority");
+                STATUS_PROJECTION, null, null, "account_type, account, authority");
         sb.append("\nSync history by account and authority\n");
         try {
             while (c.moveToNext()) {
-                if (!TextUtils.equals(currentAccount, c.getString(0))) {
+                final Account account = new Account(c.getString(0), c.getString(13));
+                if (!account.equals(currentAccount)) {
                     if (currentAccount != null) {
                         dumpSyncHistoryFooter(sb);
                     }
-                    currentAccount = c.getString(0);
+                    currentAccount = account;
                     dumpSyncHistoryHeader(sb, currentAccount);
                 }
 
@@ -1105,8 +1111,8 @@
         }
     }
 
-    private void dumpSyncHistoryHeader(StringBuilder sb, String account) {
-        sb.append(" Account: ").append(account).append("\n");
+    private void dumpSyncHistoryHeader(StringBuilder sb, Account account) {
+        sb.append(" ").append(account).append("\n");
         sb.append("  ___________________________________________________________________________________________________________________________\n");
         sb.append(" |                 |             num times synced           |   total  |         last success          |                     |\n");
         sb.append(" | authority       | local |  poll | server |  user | total | duration |  source |               time  |   result if failing |\n");
@@ -1125,7 +1131,8 @@
             Sync.Status.LAST_SUCCESS_TIME, // 9
             Sync.Status.LAST_FAILURE_SOURCE, // 10
             Sync.Status.LAST_FAILURE_TIME, // 11
-            Sync.Status.LAST_FAILURE_MESG // 12
+            Sync.Status.LAST_FAILURE_MESG, // 12
+            Sync.Status.ACCOUNT_TYPE, // 13
     };
 
     private void dumpSyncHistoryRow(StringBuilder sb, Cursor c) {
@@ -1293,7 +1300,7 @@
          */
         class SyncNotificationInfo {
             // only valid if isActive is true
-            public String account;
+            public Account account;
 
             // only valid if isActive is true
             public String authority;
@@ -1448,7 +1455,7 @@
 
             // If the accounts aren't known yet then we aren't ready to run. We will be kicked
             // when the account lookup request does complete.
-            String[] accounts = mAccounts;
+            Account[] accounts = mAccounts;
             if (accounts == null) {
                 if (isLoggable) {
                     Log.v(TAG, "runStateIdle: accounts not known, skipping");
@@ -1845,7 +1852,7 @@
             mContext.sendBroadcast(syncStateIntent);
         }
 
-        private void installHandleTooManyDeletesNotification(String account, String authority,
+        private void installHandleTooManyDeletesNotification(Account account, String authority,
                 long numDeletes) {
             if (mNotificationMgr == null) return;
             Intent clickIntent = new Intent();
@@ -1925,14 +1932,16 @@
                 "_id",
                 "authority",
                 "account",
+                "account_type",
                 "extras",
-                "source"
+                "source",
         };
         private static final int COLUMN_ID = 0;
         private static final int COLUMN_AUTHORITY = 1;
         private static final int COLUMN_ACCOUNT = 2;
-        private static final int COLUMN_EXTRAS = 3;
-        private static final int COLUMN_SOURCE = 4;
+        private static final int COLUMN_ACCOUNT_TYPE = 3;
+        private static final int COLUMN_EXTRAS = 4;
+        private static final int COLUMN_SOURCE = 5;
 
         private static final boolean DEBUG_CHECK_DATA_CONSISTENCY = false;
 
@@ -2014,7 +2023,8 @@
                     parcel.recycle();
                 }
                 ContentValues values = new ContentValues();
-                values.put("account", operation.account);
+                values.put("account", operation.account.mName);
+                values.put("account_type", operation.account.mType);
                 values.put("authority", operation.authority);
                 values.put("source", operation.syncSource);
                 values.put("extras", extrasData);
@@ -2072,7 +2082,7 @@
             if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
         }
 
-        public void clear(String account, String authority) {
+        public void clear(Account account, String authority) {
             Iterator<Map.Entry<String, SyncOperation>> entries = mOpsByKey.entrySet().iterator();
             while (entries.hasNext()) {
                 Map.Entry<String, SyncOperation> entry = entries.next();
@@ -2163,7 +2173,8 @@
             }
 
             SyncOperation syncOperation = new SyncOperation(
-                    cursor.getString(COLUMN_ACCOUNT),
+                    new Account(cursor.getString(COLUMN_ACCOUNT),
+                            cursor.getString(COLUMN_ACCOUNT_TYPE)),
                     cursor.getInt(COLUMN_SOURCE),
                     cursor.getString(COLUMN_AUTHORITY),
                     extras,
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index f503e6f..dc728ec 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -23,6 +23,7 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.net.Uri;
+import android.accounts.Account;
 
 /**
  * Extends the schema of a ContentProvider to include the _sync_state table
@@ -43,14 +44,15 @@
     private static final Uri CONTENT_URI =
             Uri.parse("content://" + SYNC_STATE_AUTHORITY + "/state");
 
-    private static final String ACCOUNT_WHERE = "_sync_account = ?";
+    private static final String ACCOUNT_WHERE = "_sync_account = ? AND _sync_account_type = ?";
 
     private final Provider mInternalProviderInterface;
 
     private static final String SYNC_STATE_TABLE = "_sync_state";
-    private static long DB_VERSION = 2;
+    private static long DB_VERSION = 3;
 
-    private static final String[] ACCOUNT_PROJECTION = new String[]{"_sync_account"};
+    private static final String[] ACCOUNT_PROJECTION =
+            new String[]{"_sync_account", "_sync_account_type"};
 
     static {
         sURIMatcher.addURI(SYNC_STATE_AUTHORITY, "state", STATE);
@@ -70,8 +72,9 @@
         db.execSQL("CREATE TABLE _sync_state (" +
                    "_id INTEGER PRIMARY KEY," +
                    "_sync_account TEXT," +
+                   "_sync_account_type TEXT," +
                    "data TEXT," +
-                   "UNIQUE(_sync_account)" +
+                   "UNIQUE(_sync_account, _sync_account_type)" +
                    ");");
 
         db.execSQL("DROP TABLE IF EXISTS _sync_state_metadata");
@@ -168,15 +171,17 @@
      * @param account the account of the row that should be copied over.
      */
     public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
-            String account) {
-        final String[] whereArgs = new String[]{account};
-        Cursor c = dbSrc.query(SYNC_STATE_TABLE, new String[]{"_sync_account", "data"},
+            Account account) {
+        final String[] whereArgs = new String[]{account.mName, account.mType};
+        Cursor c = dbSrc.query(SYNC_STATE_TABLE,
+                new String[]{"_sync_account", "_sync_account_type", "data"},
                 ACCOUNT_WHERE, whereArgs, null, null, null);
         try {
             if (c.moveToNext()) {
                 ContentValues values = new ContentValues();
                 values.put("_sync_account", c.getString(0));
-                values.put("data", c.getBlob(1));
+                values.put("_sync_account_type", c.getString(1));
+                values.put("data", c.getBlob(2));
                 dbDest.replace(SYNC_STATE_TABLE, "_sync_account", values);
             }
         } finally {
@@ -184,14 +189,17 @@
         }
     }
 
-    public void onAccountsChanged(String[] accounts) {
+    public void onAccountsChanged(Account[] accounts) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
         try {
             while (c.moveToNext()) {
-                final String account = c.getString(0);
+                final String accountName = c.getString(0);
+                final String accountType = c.getString(1);
+                Account account = new Account(accountName, accountType);
                 if (!ArrayUtils.contains(accounts, account)) {
-                    db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+                    db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE,
+                            new String[]{accountName, accountType});
                 }
             }
         } finally {
@@ -199,9 +207,9 @@
         }
     }
 
-    public void discardSyncData(SQLiteDatabase db, String account) {
+    public void discardSyncData(SQLiteDatabase db, Account account) {
         if (account != null) {
-            db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+            db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType});
         } else {
             db.delete(SYNC_STATE_TABLE, null, null);
         }
@@ -210,9 +218,9 @@
     /**
      * Retrieves the SyncData bytes for the given account. The byte array returned may be null.
      */
-    public byte[] readSyncDataBytes(SQLiteDatabase db, String account) {
+    public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
         Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
-                new String[]{account}, null, null, null);
+                new String[]{account.mName, account.mType}, null, null, null);
         try {
             if (c.moveToFirst()) {
                 return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -226,9 +234,10 @@
     /**
      * Sets the SyncData bytes for the given account. The bytes array may be null.
      */
-    public void writeSyncDataBytes(SQLiteDatabase db, String account, byte[] data) {
+    public void writeSyncDataBytes(SQLiteDatabase db, Account account, byte[] data) {
         ContentValues values = new ContentValues();
         values.put("data", data);
-        db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE, new String[]{account});
+        db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
+                new String[]{account.mName, account.mType});
     }
 }
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 282f6e7..2ad44d2 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -1,6 +1,7 @@
 package android.content;
 
 import android.Manifest;
+import android.accounts.Account;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
@@ -16,6 +17,8 @@
 import java.util.HashMap;
 import java.util.HashSet;
 
+import com.google.android.collect.Sets;
+
 /**
  * ContentProvider that tracks the sync data and overall sync
  * history on the device.
@@ -26,7 +29,7 @@
     private static final String TAG = "SyncManager";
 
     private static final String DATABASE_NAME = "syncmanager.db";
-    private static final int DATABASE_VERSION = 10;
+    private static final int DATABASE_VERSION = 11;
 
     private static final int STATS = 1;
     private static final int STATS_ID = 2;
@@ -63,17 +66,20 @@
         PENDING_PROJECTION_MAP = map = new HashMap<String,String>();
         map.put(Sync.History._ID, Sync.History._ID);
         map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT);
+        map.put(Sync.History.ACCOUNT_TYPE, Sync.History.ACCOUNT_TYPE);
         map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY);
 
         ACTIVE_PROJECTION_MAP = map = new HashMap<String,String>();
         map.put(Sync.History._ID, Sync.History._ID);
         map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT);
+        map.put(Sync.History.ACCOUNT_TYPE, Sync.History.ACCOUNT_TYPE);
         map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY);
         map.put("startTime", "startTime");
 
         HISTORY_PROJECTION_MAP = map = new HashMap<String,String>();
         map.put(Sync.History._ID, "history._id as _id");
         map.put(Sync.History.ACCOUNT, "stats.account as account");
+        map.put(Sync.History.ACCOUNT_TYPE, "stats.account_type as account_type");
         map.put(Sync.History.AUTHORITY, "stats.authority as authority");
         map.put(Sync.History.EVENT, Sync.History.EVENT);
         map.put(Sync.History.EVENT_TIME, Sync.History.EVENT_TIME);
@@ -86,6 +92,7 @@
         STATUS_PROJECTION_MAP = map = new HashMap<String,String>();
         map.put(Sync.Status._ID, "status._id as _id");
         map.put(Sync.Status.ACCOUNT, "stats.account as account");
+        map.put(Sync.Status.ACCOUNT_TYPE, "stats.account_type as account_type");
         map.put(Sync.Status.AUTHORITY, "stats.authority as authority");
         map.put(Sync.Status.TOTAL_ELAPSED_TIME, Sync.Status.TOTAL_ELAPSED_TIME);
         map.put(Sync.Status.NUM_SYNCS, Sync.Status.NUM_SYNCS);
@@ -102,7 +109,7 @@
     }
 
     private static final String[] STATS_ACCOUNT_PROJECTION =
-            new String[] { Sync.Stats.ACCOUNT };
+            new String[] { Sync.Stats.ACCOUNT, Sync.Stats.ACCOUNT_TYPE };
 
     private static final int MAX_HISTORY_EVENTS_TO_KEEP = 5000;
 
@@ -151,6 +158,7 @@
                     + "_id INTEGER PRIMARY KEY,"
                     + "authority TEXT NOT NULL,"
                     + "account TEXT NOT NULL,"
+                    + "account_type TEXT NOT NULL,"
                     + "extras BLOB NOT NULL,"
                     + "source INTEGER NOT NULL"
                     + ");");
@@ -158,6 +166,7 @@
             db.execSQL("CREATE TABLE stats (" +
                        "_id INTEGER PRIMARY KEY," +
                        "account TEXT, " +
+                       "account_type TEXT, " +
                        "authority TEXT, " +
                        "syncdata TEXT, " +
                        "UNIQUE (account, authority)" +
@@ -195,6 +204,7 @@
                     + "_id INTEGER PRIMARY KEY,"
                     + "authority TEXT,"
                     + "account TEXT,"
+                    + "account_type TEXT,"
                     + "startTime INTEGER);");
 
             db.execSQL("CREATE INDEX historyEventTime ON history (eventTime)");
@@ -206,10 +216,27 @@
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            if (oldVersion == 9 && newVersion == 10) {
+            if (oldVersion == 9) {
                 Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                         + newVersion + ", which will preserve old data");
                 db.execSQL("ALTER TABLE status ADD COLUMN initialFailureTime INTEGER");
+                oldVersion++;
+            }
+
+            if (oldVersion == 10) {
+                Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+                        + newVersion + ", which will preserve old data");
+                db.execSQL("ALTER TABLE pending ADD COLUMN account_type TEXT");
+                db.execSQL("ALTER TABLE stats ADD COLUMN account_type TEXT");
+                db.execSQL("ALTER TABLE active ADD COLUMN account_type TEXT");
+
+                db.execSQL("UPDATE pending SET account_type='com.google.GAIA'");
+                db.execSQL("UPDATE stats SET account_type='com.google.GAIA'");
+                db.execSQL("UPDATE active SET account_type='com.google.GAIA'");
+                oldVersion++;
+            }
+
+            if (oldVersion == newVersion) {
                 return;
             }
 
@@ -233,23 +260,23 @@
         }
     }
 
-    protected void doDatabaseCleanup(String[] accounts) {
-        HashSet<String> currentAccounts = new HashSet<String>();
-        for (String account : accounts) currentAccounts.add(account);
+    protected void doDatabaseCleanup(Account[] accounts) {
+        HashSet<Account> currentAccounts = Sets.newHashSet(accounts);
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         Cursor cursor = db.query("stats", STATS_ACCOUNT_PROJECTION,
-                null /* where */, null /* where args */, Sync.Stats.ACCOUNT,
+                null /* where */, null /* where args */,
+                Sync.Stats.ACCOUNT + "," + Sync.Stats.ACCOUNT_TYPE,
                 null /* having */, null /* order by */);
         try {
             while (cursor.moveToNext()) {
-                String account = cursor.getString(0);
-                if (TextUtils.isEmpty(account)) {
-                    continue;
-                }
+                String accountName = cursor.getString(0);
+                String accountType = cursor.getString(1);
+                final Account account = new Account(accountName, accountType);
                 if (!currentAccounts.contains(account)) {
-                    String where = Sync.Stats.ACCOUNT + "=?";
+                    String where = Sync.Stats.ACCOUNT + "=? AND " + Sync.Stats.ACCOUNT_TYPE + "=?";
                     int numDeleted;
-                    numDeleted = db.delete("stats", where, new String[]{account});
+                    numDeleted = db.delete("stats", where,
+                            new String[]{account.mName, account.mType});
                     if (Config.LOGD) {
                         Log.d(TAG, "deleted " + numDeleted
                                 + " records from stats table"
@@ -272,10 +299,11 @@
         }
     }
 
-    private int updateActiveSync(String account, String authority, Long startTime) {
+    private int updateActiveSync(Account account, String authority, Long startTime) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         ContentValues values = new ContentValues();
-        values.put("account", account);
+        values.put("account", account == null ? null : account.mName);
+        values.put("account_type", account == null ? null : account.mType);
         values.put("authority", authority);
         values.put("startTime", startTime);
         int numChanges = db.update("active", values, null, null);
@@ -463,7 +491,9 @@
             db.beginTransaction();
             long rowId = db.insert("pending", Sync.Pending.ACCOUNT, values);
             if (rowId < 0) return null;
-            String account = values.getAsString(Sync.Pending.ACCOUNT);
+            String accountName = values.getAsString(Sync.Pending.ACCOUNT);
+            String accountType = values.getAsString(Sync.Pending.ACCOUNT_TYPE);
+            final Account account = new Account(accountName, accountType);
             String authority = values.getAsString(Sync.Pending.AUTHORITY);
 
             long statsId = createStatsRowIfNecessary(account, authority);
@@ -491,25 +521,31 @@
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         db.beginTransaction();
         try {
-            String account;
+            Account account;
             String authority;
             Cursor c = db.query("pending",
-                    new String[]{Sync.Pending.ACCOUNT, Sync.Pending.AUTHORITY},
+                    new String[]{Sync.Pending.ACCOUNT, Sync.Pending.ACCOUNT_TYPE,
+                            Sync.Pending.AUTHORITY},
                     "_id=" + rowId, null, null, null, null);
             try {
                 if (c.getCount() != 1) {
                     return 0;
                 }
                 c.moveToNext();
-                account = c.getString(0);
-                authority = c.getString(1);
+                String accountName = c.getString(0);
+                String accountType = c.getString(1);
+                account = new Account(accountName, accountType);
+                authority = c.getString(2);
             } finally {
                 c.close();
             }
             db.delete("pending", "_id=" + rowId, null /* no where args */);
-            final String[] accountAuthorityWhereArgs = new String[]{account, authority};
+            final String[] accountAuthorityWhereArgs =
+                    new String[]{account.mName, account.mType, authority};
             boolean isPending = 0 < DatabaseUtils.longForQuery(db,
-                    "SELECT COUNT(*) FROM PENDING WHERE account=? AND authority=?",
+                    "SELECT COUNT(*)"
+                            + " FROM PENDING"
+                            + " WHERE account=? AND account_type=? AND authority=?",
                     accountAuthorityWhereArgs);
             if (!isPending) {
                 long statsId = createStatsRowIfNecessary(account, authority);
@@ -581,7 +617,7 @@
         return numDeletes > 0;
     }
 
-    public long insertStartSyncEvent(String account, String authority, long now, int source) {
+    public long insertStartSyncEvent(Account account, String authority, long now, int source) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         long statsId = createStatsRowIfNecessary(account, authority);
 
@@ -731,14 +767,15 @@
         }
     }
 
-    private long createStatsRowIfNecessary(String account, String authority) {
+    private long createStatsRowIfNecessary(Account account, String authority) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         StringBuilder where = new StringBuilder();
         where.append(Sync.Stats.ACCOUNT + "= ?");
+        where.append(" and " + Sync.Stats.ACCOUNT_TYPE + "= ?");
         where.append(" and " + Sync.Stats.AUTHORITY + "= ?");
         Cursor cursor = query(Sync.Stats.CONTENT_URI,
                 Sync.Stats.SYNC_STATS_PROJECTION,
-                where.toString(), new String[] { account, authority },
+                where.toString(), new String[] { account.mName, account.mType, authority },
                 null /* order */);
         try {
             long id;
@@ -746,7 +783,8 @@
                 id = cursor.getLong(cursor.getColumnIndexOrThrow(Sync.Stats._ID));
             } else {
                 ContentValues values = new ContentValues();
-                values.put(Sync.Stats.ACCOUNT, account);
+                values.put(Sync.Stats.ACCOUNT, account.mName);
+                values.put(Sync.Stats.ACCOUNT_TYPE, account.mType);
                 values.put(Sync.Stats.AUTHORITY, authority);
                 id = db.insert("stats", null, values);
             }
diff --git a/core/java/android/content/SyncableContentProvider.java b/core/java/android/content/SyncableContentProvider.java
index e0cd786..93ebbea 100644
--- a/core/java/android/content/SyncableContentProvider.java
+++ b/core/java/android/content/SyncableContentProvider.java
@@ -19,6 +19,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
+import android.accounts.Account;
 
 import java.util.Map;
 
@@ -110,7 +111,7 @@
      * @param context the sync context for the operation
      * @param account
      */
-    public abstract void onSyncStart(SyncContext context, String account);
+    public abstract void onSyncStart(SyncContext context, Account account);
 
     /**
      * Called right after a sync is completed
@@ -124,7 +125,7 @@
      * The account of the most recent call to onSyncStart()
      * @return the account
      */
-    public abstract String getSyncingAccount();
+    public abstract Account getSyncingAccount();
 
     /**
      * Merge diffs from a sync source with this content provider.
@@ -194,7 +195,7 @@
      * Make sure that there are no entries for accounts that no longer exist
      * @param accountsArray the array of currently-existing accounts
      */
-    protected abstract void onAccountsChanged(String[] accountsArray);
+    protected abstract void onAccountsChanged(Account[] accountsArray);
 
     /**
      * A helper method to delete all rows whose account is not in the accounts
@@ -203,26 +204,24 @@
      *
      * @param accounts a map of existing accounts
      * @param table the table to delete from
-     * @param accountColumnName the name of the column that is expected
-     * to hold the account.
      */
-    protected abstract void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
-            String table, String accountColumnName);
+    protected abstract void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts,
+            String table);
 
     /**
      * Called when the sync system determines that this provider should no longer
      * contain records for the specified account.
      */
-    public abstract void wipeAccount(String account);
+    public abstract void wipeAccount(Account account);
 
     /**
      * Retrieves the SyncData bytes for the given account. The byte array returned may be null.
      */
-    public abstract byte[] readSyncDataBytes(String account);
+    public abstract byte[] readSyncDataBytes(Account account);
 
     /**
      * Sets the SyncData bytes for the given account. The bytes array may be null.
      */
-    public abstract void writeSyncDataBytes(String account, byte[] data);
+    public abstract void writeSyncDataBytes(Account account, byte[] data);
 }
 
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index eb3a5da..0cbe01e 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -12,6 +12,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.TimingLogger;
+import android.accounts.Account;
 
 /**
  * @hide
@@ -67,7 +68,7 @@
      * @return true, if the sync was successfully started. One reason it can
      *   fail to start is if there is no user configured on the device.
      */
-    public abstract void onSyncStarting(SyncContext context, String account, boolean forced,
+    public abstract void onSyncStarting(SyncContext context, Account account, boolean forced,
             SyncResult result);
 
     /**
@@ -168,12 +169,12 @@
      * exist.
      * @param accounts the list of accounts
      */
-    public abstract void onAccountsChanged(String[] accounts);
+    public abstract void onAccountsChanged(Account[] accounts);
 
     private Context mContext;
 
     private class SyncThread extends Thread {
-        private final String mAccount;
+        private final Account mAccount;
         private final Bundle mExtras;
         private final SyncContext mSyncContext;
         private volatile boolean mIsCanceled = false;
@@ -181,7 +182,7 @@
         private long mInitialRxBytes;
         private final SyncResult mResult;
 
-        SyncThread(SyncContext syncContext, String account, Bundle extras) {
+        SyncThread(SyncContext syncContext, Account account, Bundle extras) {
             super("SyncThread");
             mAccount = account;
             mExtras = extras;
@@ -221,7 +222,7 @@
             }
         }
 
-        private void sync(SyncContext syncContext, String account, Bundle extras) {
+        private void sync(SyncContext syncContext, Account account, Bundle extras) {
             mIsCanceled = false;
 
             mProviderSyncStarted = false;
@@ -273,7 +274,7 @@
             }
         }
 
-        private void runSyncLoop(SyncContext syncContext, String account, Bundle extras) {
+        private void runSyncLoop(SyncContext syncContext, Account account, Bundle extras) {
             TimingLogger syncTimer = new TimingLogger(TAG + "Profiling", "sync");
             syncTimer.addSplit("start");
             int loopCount = 0;
@@ -518,7 +519,7 @@
         EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, "");
     }
 
-    public void startSync(SyncContext syncContext, String account, Bundle extras) {
+    public void startSync(SyncContext syncContext, Account account, Bundle extras) {
         if (mSyncThread != null) {
             syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
             return;
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 10f3806..78ef374 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -211,7 +211,7 @@
             sb.append(sqlString);
         sb.append('\'');
     }
-    
+
     /**
      * SQL-escape a string.
      */
@@ -240,7 +240,7 @@
             appendEscapedSQLString(sql, value.toString());
         }
     }
-    
+
     /**
      * Concatenates two SQL WHERE clauses, handling empty or null values.
      * @hide
@@ -252,12 +252,12 @@
         if (TextUtils.isEmpty(b)) {
             return a;
         }
-            
+
         return "(" + a + ") AND (" + b + ")";
     }
-    
+
     /**
-     * return the collation key 
+     * return the collation key
      * @param name
      * @return the collation key
      */
@@ -269,7 +269,7 @@
             return "";
         }
     }
-    
+
     /**
      * return the collation key in hex format
      * @param name
@@ -280,7 +280,7 @@
         char[] keys = Hex.encodeHex(arr);
         return new String(keys, 0, getKeyLen(arr) * 2);
     }
-    
+
     private static int getKeyLen(byte[] arr) {
         if (arr[arr.length - 1] != 0) {
             return arr.length;
@@ -289,16 +289,16 @@
             return arr.length-1;
         }
     }
-    
+
     private static byte[] getCollationKeyInBytes(String name) {
         if (mColl == null) {
             mColl = Collator.getInstance();
             mColl.setStrength(Collator.PRIMARY);
         }
-        return mColl.getCollationKey(name).toByteArray();        
+        return mColl.getCollationKey(name).toByteArray();
     }
-    
-    private static Collator mColl = null;    
+
+    private static Collator mColl = null;
     /**
      * Prints the contents of a Cursor to System.out. The position is restored
      * after printing.
@@ -591,10 +591,12 @@
     public static long queryNumEntries(SQLiteDatabase db, String table) {
         Cursor cursor = db.query(table, countProjection,
                 null, null, null, null, null);
-        cursor.moveToFirst();
-        long count = cursor.getLong(0);
-        cursor.deactivate();
-        return count;
+        try {
+            cursor.moveToFirst();
+            return cursor.getLong(0);
+        } finally {
+            cursor.close();
+        }
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 519a81c..139fcba 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -351,23 +351,26 @@
             String groupBy, String having, String sortOrder, String limit) {
         String[] projection = computeProjection(projectionIn);
 
+        StringBuilder where = new StringBuilder();
+
         if (mWhereClause.length() > 0) {
-            mWhereClause.append(')');
+            where.append(mWhereClause.toString());
+            where.append(')');
         }
 
         // Tack on the user's selection, if present.
         if (selection != null && selection.length() > 0) {
             if (mWhereClause.length() > 0) {
-                mWhereClause.append(" AND ");
+                where.append(" AND ");
             }
 
-            mWhereClause.append('(');
-            mWhereClause.append(selection);
-            mWhereClause.append(')');
+            where.append('(');
+            where.append(selection);
+            where.append(')');
         }
 
         return buildQueryString(
-                mDistinct, mTables, projection, mWhereClause.toString(),
+                mDistinct, mTables, projection, where.toString(),
                 groupBy, having, sortOrder, limit);
     }
 
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index f4a2a6a..f6159de 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -54,7 +54,7 @@
     static Pattern sAddressPattern = Pattern.compile(
             /* scheme    */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
             /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
-            /* host      */ "([-A-Za-z0-9%]+(?:\\.[-A-Za-z0-9%]+)*)?" +
+            /* host      */ "([-A-Za-z0-9%_]+(?:\\.[-A-Za-z0-9%_]+)*)?" +
             /* port      */ "(?:\\:([0-9]+))?" +
             /* path      */ "(\\/?.*)?");
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 5ea5aae..e73a97e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -633,6 +633,25 @@
     public static final native int getBinderDeathObjectCount();
 
     /**
+     * Primes the register map cache.
+     *
+     * Only works for classes in the bootstrap class loader.  Does not
+     * cause classes to be loaded if they're not already present.
+     *
+     * The classAndMethodDesc argument is a concatentation of the VM-internal
+     * class descriptor, method name, and method descriptor.  Examples:
+     *     Landroid/os/Looper;.loop:()V
+     *     Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
+     *
+     * @param classAndMethodDesc the method to prepare
+     *
+     * @hide
+     */
+    public static final boolean cacheRegisterMap(String classAndMethodDesc) {
+        return VMDebug.cacheRegisterMap(classAndMethodDesc);
+    }
+
+    /**
      * API for gathering and querying instruction counts.
      *
      * Example usage:
diff --git a/core/java/android/os/Exec.java b/core/java/android/os/Exec.java
deleted file mode 100644
index a50d5fe..0000000
--- a/core/java/android/os/Exec.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2007 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.os;
-
-import java.io.FileDescriptor;
-
-/**
- * @hide
- * Tools for executing commands.  Not for public consumption.
- */
-
-public class Exec
-{
-    /**
-     * @param cmd The command to execute
-     * @param arg0 The first argument to the command, may be null
-     * @param arg1 the second argument to the command, may be null
-     * @return the file descriptor of the started process.
-     * 
-     */
-    public static FileDescriptor createSubprocess(
-        String cmd, String arg0, String arg1) {
-        return createSubprocess(cmd, arg0, arg1, null);
-    }
-    
-    /**
-     * @param cmd The command to execute
-     * @param arg0 The first argument to the command, may be null
-     * @param arg1 the second argument to the command, may be null
-     * @param processId A one-element array to which the process ID of the
-     * started process will be written.
-     * @return the file descriptor of the started process.
-     * 
-     */
-     public static native FileDescriptor createSubprocess(
-        String cmd, String arg0, String arg1, int[] processId);
-    
-     public static native void setPtyWindowSize(FileDescriptor fd,
-       int row, int col, int xpixel, int ypixel);
-    /**
-     * Causes the calling thread to wait for the process associated with the
-     * receiver to finish executing.
-     * 
-     * @return The exit value of the Process being waited on
-     * 
-     */
-    public static native int waitFor(int processId);
-}
-
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 63f6dff..50a9a83 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -22,7 +22,7 @@
  * Takes care of the grunt work of maintaining a list of remote interfaces,
  * typically for the use of performing callbacks from a
  * {@link android.app.Service} to its clients.  In particular, this:
- * 
+ *
  * <ul>
  * <li> Keeps track of a set of registered {@link IInterface} callbacks,
  * taking care to identify them through their underlying unique {@link IBinder}
@@ -34,13 +34,13 @@
  * multithreaded incoming calls, and a thread-safe way to iterate over a
  * snapshot of the list without holding its lock.
  * </ul>
- * 
+ *
  * <p>To use this class, simply create a single instance along with your
  * service, and call its {@link #register} and {@link #unregister} methods
  * as client register and unregister with your service.  To call back on to
  * the registered clients, use {@link #beginBroadcast},
  * {@link #getBroadcastItem}, and {@link #finishBroadcast}.
- * 
+ *
  * <p>If a registered callback's process goes away, this class will take
  * care of automatically removing it from the list.  If you want to do
  * additional work in this situation, you can create a subclass that
@@ -51,14 +51,14 @@
             = new HashMap<IBinder, Callback>();
     private IInterface[] mActiveBroadcast;
     private boolean mKilled = false;
-    
+
     private final class Callback implements IBinder.DeathRecipient {
         final E mCallback;
-        
+
         Callback(E callback) {
             mCallback = callback;
         }
-        
+
         public void binderDied() {
             synchronized (mCallbacks) {
                 mCallbacks.remove(mCallback.asBinder());
@@ -66,7 +66,7 @@
             onCallbackDied(mCallback);
         }
     }
-    
+
     /**
      * Add a new callback to the list.  This callback will remain in the list
      * until a corresponding call to {@link #unregister} or its hosting process
@@ -75,17 +75,17 @@
      * object is already in the list), then it will be left as-is.
      * Registrations are not counted; a single call to {@link #unregister}
      * will remove a callback after any number calls to register it.
-     * 
+     *
      * @param callback The callback interface to be added to the list.  Must
      * not be null -- passing null here will cause a NullPointerException.
      * Most services will want to check for null before calling this with
      * an object given from a client, so that clients can't crash the
      * service with bad data.
-     * 
+     *
      * @return Returns true if the callback was successfully added to the list.
      * Returns false if it was not added, either because {@link #kill} had
      * previously been called or the callback's process has gone away.
-     * 
+     *
      * @see #unregister
      * @see #kill
      * @see #onCallbackDied
@@ -106,7 +106,7 @@
             }
         }
     }
-    
+
     /**
      * Remove from the list a callback that was previously added with
      * {@link #register}.  This uses the
@@ -114,14 +114,14 @@
      * find the previous registration.
      * Registrations are not counted; a single unregister call will remove
      * a callback after any number calls to {@link #register} for it.
-     * 
+     *
      * @param callback The callback to be removed from the list.  Passing
      * null here will cause a NullPointerException, so you will generally want
      * to check for null before calling.
-     * 
+     *
      * @return Returns true if the callback was found and unregistered.  Returns
      * false if the given callback was not found on the list.
-     * 
+     *
      * @see #register
      */
     public boolean unregister(E callback) {
@@ -134,13 +134,13 @@
             return false;
         }
     }
-    
+
     /**
      * Disable this callback list.  All registered callbacks are unregistered,
      * and the list is disabled so that future calls to {@link #register} will
      * fail.  This should be used when a Service is stopping, to prevent clients
      * from registering callbacks after it is stopped.
-     * 
+     *
      * @see #register
      */
     public void kill() {
@@ -152,21 +152,21 @@
             mKilled = true;
         }
     }
-    
+
     /**
      * Called when the process hosting a callback in the list has gone away.
      * The default implementation does nothing.
-     * 
+     *
      * @param callback The callback whose process has died.  Note that, since
      * its process has died, you can not make any calls on to this interface.
      * You can, however, retrieve its IBinder and compare it with another
      * IBinder to see if it is the same object.
-     * 
+     *
      * @see #register
      */
     public void onCallbackDied(E callback) {
     }
-    
+
     /**
      * Prepare to start making calls to the currently registered callbacks.
      * This creates a copy of the callback list, which you can retrieve items
@@ -175,12 +175,12 @@
      * same thread (usually by scheduling with {@link Handler} or
      * do your own synchronization.  You must call {@link #finishBroadcast}
      * when done.
-     * 
+     *
      * <p>A typical loop delivering a broadcast looks like this:
-     * 
+     *
      * <pre>
      * final int N = callbacks.beginBroadcast();
-     * for (int i=0; i<N; i++) {
+     * for (int i=0; i&lt;N; i++) {
      *     try {
      *         callbacks.getBroadcastItem(i).somethingHappened();
      *     } catch (RemoteException e) {
@@ -189,11 +189,11 @@
      *     }
      * }
      * callbacks.finishBroadcast();</pre>
-     * 
+     *
      * @return Returns the number of callbacks in the broadcast, to be used
      * with {@link #getBroadcastItem} to determine the range of indices you
      * can supply.
-     * 
+     *
      * @see #getBroadcastItem
      * @see #finishBroadcast
      */
@@ -214,37 +214,37 @@
             return i;
         }
     }
-    
+
     /**
      * Retrieve an item in the active broadcast that was previously started
      * with {@link #beginBroadcast}.  This can <em>only</em> be called after
      * the broadcast is started, and its data is no longer valid after
      * calling {@link #finishBroadcast}.
-     * 
+     *
      * <p>Note that it is possible for the process of one of the returned
      * callbacks to go away before you call it, so you will need to catch
      * {@link RemoteException} when calling on to the returned object.
      * The callback list itself, however, will take care of unregistering
      * these objects once it detects that it is no longer valid, so you can
      * handle such an exception by simply ignoring it.
-     * 
+     *
      * @param index Which of the registered callbacks you would like to
      * retrieve.  Ranges from 0 to 1-{@link #beginBroadcast}.
-     * 
+     *
      * @return Returns the callback interface that you can call.  This will
      * always be non-null.
-     * 
+     *
      * @see #beginBroadcast
      */
     public E getBroadcastItem(int index) {
         return (E)mActiveBroadcast[index];
     }
-    
+
     /**
      * Clean up the state of a broadcast previously initiated by calling
      * {@link #beginBroadcast}.  This must always be called when you are done
      * with a broadcast.
-     * 
+     *
      * @see #beginBroadcast
      */
     public void finishBroadcast() {
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 6beb06d..b46f180 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -31,8 +31,9 @@
  * The chosen ringtone's URI will be persisted as a string.
  * <p>
  * If the user chooses the "Default" item, the saved string will be one of
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI}. If the user chooses the "Silent"
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent"
  * item, the saved string will be an empty string.
  * 
  * @attr ref android.R.styleable#RingtonePreference_ringtoneType
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 20702a1..abdcd93 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -22,6 +22,7 @@
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.media.AudioManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
@@ -147,10 +148,16 @@
                     System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
                     false, mVolumeObserver);
     
-            mRingtone = RingtoneManager.getRingtone(mContext,
-                    mStreamType == AudioManager.STREAM_NOTIFICATION
-                            ? Settings.System.DEFAULT_NOTIFICATION_URI
-                            : Settings.System.DEFAULT_RINGTONE_URI);
+            Uri defaultUri = null;
+            if (mStreamType == AudioManager.STREAM_RING) {
+                defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+            } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
+                defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+            } else {
+                defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+            }
+
+            mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
             mRingtone.setStreamType(mStreamType);
         }
         
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 4a709f6..3a221e4 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -32,6 +32,7 @@
 import android.text.format.Time;
 import android.util.Config;
 import android.util.Log;
+import android.accounts.Account;
 import com.android.internal.database.ArrayListCursor;
 import com.google.android.gdata.client.AndroidGDataClient;
 import com.google.android.gdata.client.AndroidXmlParserFactory;
@@ -157,11 +158,12 @@
          * @param account the account whose rows should be deleted
          * @return the count of rows that were deleted
          */
-        public static int deleteCalendarsForAccount(ContentResolver cr,
-                String account) {
+        public static int deleteCalendarsForAccount(ContentResolver cr, Account account) {
             // delete all calendars that match this account
-            return Calendar.Calendars.delete(cr, Calendar.Calendars._SYNC_ACCOUNT + "=?",
-                    new String[] {account});
+            return Calendar.Calendars.delete(cr,
+                    Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
+                            + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
+                    new String[] {account.mName, account.mType});
         }
 
         /**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 3141f1a..a6450f3 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -30,6 +30,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.widget.ImageView;
+import android.accounts.Account;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -75,6 +76,12 @@
         public static final String _SYNC_ACCOUNT = "_sync_account";
 
         /**
+         * The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null.
+         * <P>Type: TEXT</P>
+         */
+        public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+        /**
          * The key of this setting.
          * <P>Type: TEXT</P>
          */
@@ -134,6 +141,7 @@
                 selectString = (account == null)
                         ? "_sync_account is null AND key=?"
                         : "_sync_account=? AND key=?";
+//                : "_sync_account=? AND _sync_account_type=? AND key=?";
                 selectArgs = (account == null)
                 ? new String[]{key}
                 : new String[]{account, key};
@@ -158,7 +166,8 @@
             // the account name is, so we're using a global setting for SYNC_EVERYTHING.
             // Some day when we add multiple accounts to the UI this should honor the account
             // that was asked for.
-            //values.put(_SYNC_ACCOUNT, account);
+            //values.put(_SYNC_ACCOUNT, account.mName);
+            //values.put(_SYNC_ACCOUNT_TYPE, account.mType);
             values.put(KEY, key);
             values.put(VALUE, value);
             cr.update(Settings.CONTENT_URI, values, null, null);
@@ -840,6 +849,12 @@
         public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
 
         /**
+         * The account type of the group.
+         * <P>Type: TEXT</P>
+         */
+        public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+
+        /**
          * The row id of the person.
          * <P>Type: TEXT</P>
          */
@@ -1206,7 +1221,7 @@
      */
     public interface OrganizationColumns {
         /**
-         * The type of the the phone number.
+         * The type of the organizations.
          * <P>Type: INTEGER (one of the constants below)</P>
          */
         public static final String TYPE = "type";
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 4c58e0d..790fe5c 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -63,7 +63,7 @@
      * that had initiated a download when that download completes. The
      * download's content: uri is specified in the intent's data.
      */
-    public static final String DOWNLOAD_COMPLETED_ACTION =
+    public static final String ACTION_DOWNLOAD_COMPLETED =
             "android.intent.action.DOWNLOAD_COMPLETED";
 
     /**
@@ -76,7 +76,7 @@
      * Note: this is not currently sent for downloads that have completed
      * successfully.
      */
-    public static final String NOTIFICATION_CLICKED_ACTION =
+    public static final String ACTION_NOTIFICATION_CLICKED =
             "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
 
     /**
@@ -84,14 +84,14 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
      */
-    public static final String URI = "uri";
+    public static final String COLUMN_URI = "uri";
 
     /**
      * The name of the column containing application-specific data.
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read/Write</P>
      */
-    public static final String APP_DATA = "entity";
+    public static final String COLUMN_APP_DATA = "entity";
 
     /**
      * The name of the column containing the flags that indicates whether
@@ -104,7 +104,7 @@
      * <P>Type: BOOLEAN</P>
      * <P>Owner can Init</P>
      */
-    public static final String NO_INTEGRITY = "no_integrity";
+    public static final String COLUMN_NO_INTEGRITY = "no_integrity";
 
     /**
      * The name of the column containing the filename that the initiating
@@ -113,7 +113,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init</P>
      */
-    public static final String FILENAME_HINT = "hint";
+    public static final String COLUMN_FILE_NAME_HINT = "hint";
 
     /**
      * The name of the column containing the filename where the downloaded data
@@ -128,7 +128,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
      */
-    public static final String MIMETYPE = "mimetype";
+    public static final String COLUMN_MIME_TYPE = "mimetype";
 
     /**
      * The name of the column containing the flag that controls the destination
@@ -136,7 +136,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Init</P>
      */
-    public static final String DESTINATION = "destination";
+    public static final String COLUMN_DESTINATION = "destination";
 
     /**
      * The name of the column containing the flags that controls whether the
@@ -145,7 +145,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Init/Read/Write</P>
      */
-    public static final String VISIBILITY = "visibility";
+    public static final String COLUMN_VISIBILITY = "visibility";
 
     /**
      * The name of the column containing the current control state  of the download.
@@ -154,7 +154,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
      */
-    public static final String CONTROL = "control";
+    public static final String COLUMN_CONTROL = "control";
 
     /**
      * The name of the column containing the current status of the download.
@@ -163,7 +163,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
      */
-    public static final String STATUS = "status";
+    public static final String COLUMN_STATUS = "status";
 
     /**
      * The name of the column containing the date at which some interesting
@@ -172,7 +172,7 @@
      * <P>Type: BIGINT</P>
      * <P>Owner can Read</P>
      */
-    public static final String LAST_MODIFICATION = "lastmod";
+    public static final String COLUMN_LAST_MODIFICATION = "lastmod";
 
     /**
      * The name of the column containing the package name of the application
@@ -181,7 +181,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
      */
-    public static final String NOTIFICATION_PACKAGE = "notificationpackage";
+    public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
 
     /**
      * The name of the column containing the component name of the class that
@@ -191,7 +191,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read</P>
      */
-    public static final String NOTIFICATION_CLASS = "notificationclass";
+    public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
 
     /**
      * If extras are specified when requesting a download they will be provided in the intent that
@@ -199,7 +199,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init</P>
      */
-    public static final String NOTIFICATION_EXTRAS = "notificationextras";
+    public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
 
     /**
      * The name of the column contain the values of the cookie to be used for
@@ -208,7 +208,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init</P>
      */
-    public static final String COOKIE_DATA = "cookiedata";
+    public static final String COLUMN_COOKIE_DATA = "cookiedata";
 
     /**
      * The name of the column containing the user agent that the initiating
@@ -216,7 +216,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init</P>
      */
-    public static final String USER_AGENT = "useragent";
+    public static final String COLUMN_USER_AGENT = "useragent";
 
     /**
      * The name of the column containing the referer (sic) that the initiating
@@ -224,7 +224,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init</P>
      */
-    public static final String REFERER = "referer";
+    public static final String COLUMN_REFERER = "referer";
 
     /**
      * The name of the column containing the total size of the file being
@@ -232,7 +232,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
      */
-    public static final String TOTAL_BYTES = "total_bytes";
+    public static final String COLUMN_TOTAL_BYTES = "total_bytes";
 
     /**
      * The name of the column containing the size of the part of the file that
@@ -240,7 +240,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Read</P>
      */
-    public static final String CURRENT_BYTES = "current_bytes";
+    public static final String COLUMN_CURRENT_BYTES = "current_bytes";
 
     /**
      * The name of the column where the initiating application can provide the
@@ -252,7 +252,7 @@
      * <P>Type: INTEGER</P>
      * <P>Owner can Init</P>
      */
-    public static final String OTHER_UID = "otheruid";
+    public static final String COLUMN_OTHER_UID = "otheruid";
 
     /**
      * The name of the column where the initiating application can provided the
@@ -261,7 +261,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read/Write</P>
      */
-    public static final String TITLE = "title";
+    public static final String COLUMN_TITLE = "title";
 
     /**
      * The name of the column where the initiating application can provide the
@@ -270,7 +270,7 @@
      * <P>Type: TEXT</P>
      * <P>Owner can Init/Read/Write</P>
      */
-    public static final String DESCRIPTION = "description";
+    public static final String COLUMN_DESCRIPTION = "description";
 
     /*
      * Lists the destinations that an application can specify for a download.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4dd6524..db79eb9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1174,6 +1174,22 @@
         public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
 
         /**
+         * Persistent store for the system-wide default alarm alert.
+         *
+         * @see #RINGTONE
+         * @see #DEFAULT_ALARM_ALERT_URI
+         */
+        public static final String ALARM_ALERT = "alarm_alert";
+
+        /**
+         * A {@link Uri} that will point to the current default alarm alert at
+         * any given time.
+         *
+         * @see #DEFAULT_ALARM_ALERT_URI
+         */
+        public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
+
+        /**
          * Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_REPLACE = "auto_replace";
@@ -2561,6 +2577,11 @@
                 "gtalk_ssl_handshake_timeout_ms";
 
         /**
+         * Compress the gtalk stream.
+         */
+        public static final String GTALK_COMPRESS = "gtalk_compress";
+
+        /**
          * Enable use of ssl session caching.
          * 'db' - save each session in a (per process) database
          * 'file' - save each session in a (per process) file
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index 4d430d5..f94b442 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -20,6 +20,7 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
+import android.accounts.Account;
 
 /**
  * The SubscribedFeeds provider stores all information about subscribed feeds.
@@ -99,7 +100,7 @@
         /**
          * The default sort order for this table
          */
-        public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+        public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
     }
 
     /**
@@ -114,38 +115,36 @@
      * @return  the Uri of the feed that was added
      */
     public static Uri addFeed(ContentResolver resolver,
-            String feed, String account,
+            String feed, Account account,
             String authority, String service) {
         ContentValues values = new ContentValues();
         values.put(SubscribedFeeds.Feeds.FEED, feed);
-        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account);
+        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName);
+        values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType);
         values.put(SubscribedFeeds.Feeds.AUTHORITY, authority);
         values.put(SubscribedFeeds.Feeds.SERVICE, service);
         return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values);
     }
 
     public static int deleteFeed(ContentResolver resolver,
-            String feed, String account, String authority) {
+            String feed, Account account, String authority) {
         StringBuilder where = new StringBuilder();
         where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+        where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
         where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
         where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
         return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
-                where.toString(), new String[] {account, feed, authority});
+                where.toString(), new String[] {account.mName, account.mType, feed, authority});
     }
 
     public static int deleteFeeds(ContentResolver resolver,
-            String account, String authority) {
+            Account account, String authority) {
         StringBuilder where = new StringBuilder();
         where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+        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, authority});
-    }
-
-    public static String gtalkServiceRoutingInfoFromAccountAndResource(
-            String account, String res) {
-        return Uri.parse("gtalk://" + account + "/" + res).toString();
+                where.toString(), new String[] {account.mName, account.mType, authority});
     }
 
     /**
@@ -157,6 +156,12 @@
          * <P>Type: TEXT</P>
          */
         public static final String _SYNC_ACCOUNT = SyncConstValue._SYNC_ACCOUNT;
+
+        /**
+         * The account type.
+         * <P>Type: TEXT</P>
+         */
+        public static final String _SYNC_ACCOUNT_TYPE = SyncConstValue._SYNC_ACCOUNT_TYPE;
     }
 
     /**
@@ -199,6 +204,6 @@
         /**
          * The default sort order for this table
          */
-        public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+        public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
     }
 }
diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java
index 628852f..c9bde0e 100644
--- a/core/java/android/provider/Sync.java
+++ b/core/java/android/provider/Sync.java
@@ -22,6 +22,8 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Handler;
+import android.accounts.Account;
+import android.text.TextUtils;
 
 import java.util.Map;
 
@@ -51,6 +53,12 @@
         public static final String ACCOUNT = "account";
 
         /**
+         * The sync account type.
+         * <P>Type: TEXT</P>
+         */
+        public static final String ACCOUNT_TYPE = "account_type";
+
+        /**
          * The content authority (contacts, calendar, etc.).
          * <P>Type: TEXT</P>
          */
@@ -280,7 +288,8 @@
         public static final String MESG_CANCELED = "canceled";
 
         private static final String FINISHED_SINCE_WHERE_CLAUSE = EVENT + "=" + EVENT_STOP
-                + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + AUTHORITY + "=?";
+                + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + ACCOUNT_TYPE + "=?"
+                + " AND " + AUTHORITY + "=?";
 
         public static String mesgToString(String mesg) {
             if (MESG_SUCCESS.equals(mesg)) return mesg;
@@ -311,10 +320,11 @@
         }
 
         public static boolean hasNewerSyncFinished(ContentResolver contentResolver,
-                String account, String authority, long when) {
+                Account account, String authority, long when) {
             Cursor c = contentResolver.query(CONTENT_URI, new String[]{_ID},
                     FINISHED_SINCE_WHERE_CLAUSE,
-                    new String[]{Long.toString(when), account, authority}, null);
+                    new String[]{Long.toString(when), account.mName, account.mType, authority},
+                    null);
             try {
               return c.getCount() > 0;
             } finally {
@@ -345,7 +355,8 @@
          * @return the cursor on the AuthorityHistory table
          */
         public static Cursor query(ContentResolver contentResolver) {
-            return contentResolver.query(CONTENT_URI, null, null, null, ACCOUNT + ", " + AUTHORITY);
+            return contentResolver.query(CONTENT_URI, null, null, null,
+                    ACCOUNT_TYPE + "," + ACCOUNT + "," + AUTHORITY);
         }
 
         public static class QueryMap extends ContentQueryMap {
@@ -356,10 +367,11 @@
                         _ID, keepUpdated, handlerForUpdateNotifications);
             }
 
-            public ContentValues get(String account, String authority) {
+            public ContentValues get(Account account, String authority) {
                 Map<String, ContentValues> rows = getRows();
                 for (ContentValues values : rows.values()) {
-                    if (values.getAsString(ACCOUNT).equals(account)
+                    if (values.getAsString(ACCOUNT).equals(account.mName)
+                            && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
                             && values.getAsString(AUTHORITY).equals(authority)) {
                         return values;
                     }
@@ -390,10 +402,11 @@
                         handlerForUpdateNotifications);
             }
 
-            public boolean isPending(String account, String authority) {
+            public boolean isPending(Account account, String authority) {
                 Map<String, ContentValues> rows = getRows();
                 for (ContentValues values : rows.values()) {
-                    if (values.getAsString(ACCOUNT).equals(account)
+                    if (values.getAsString(ACCOUNT).equals(account.mName)
+                            && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
                             && values.getAsString(AUTHORITY).equals(authority)) {
                         return true;
                     }
@@ -444,9 +457,12 @@
                 return null;
             }
 
-            public String getSyncingAccount() {
+            public Account getSyncingAccount() {
                 ContentValues values = getActiveSyncInfo();
-                return (values == null) ? null : values.getAsString(ACCOUNT);
+                if (values == null || TextUtils.isEmpty(values.getAsString(ACCOUNT))) {
+                    return null;
+                }
+                return new Account(values.getAsString(ACCOUNT), values.getAsString(ACCOUNT_TYPE));
             }
 
             public String getSyncingAuthority() {
diff --git a/core/java/android/provider/SyncConstValue.java b/core/java/android/provider/SyncConstValue.java
index 6eb4398..30966eb 100644
--- a/core/java/android/provider/SyncConstValue.java
+++ b/core/java/android/provider/SyncConstValue.java
@@ -29,6 +29,12 @@
     public static final String _SYNC_ACCOUNT = "_sync_account";
 
     /**
+     * The type of the account that was used to sync the entry to the device.
+     * <P>Type: TEXT</P>
+     */
+    public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+    /**
      * The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
      * <P>Type: TEXT</P>
      */
@@ -68,4 +74,9 @@
      * Used to indicate that this account is not synced
      */
     public static final String NON_SYNCABLE_ACCOUNT = "non_syncable";
+
+    /**
+     * Used to indicate that this account is not synced
+     */
+    public static final String NON_SYNCABLE_ACCOUNT_TYPE = "android.local";
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 61dca4c..71da9cf 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -30,8 +30,9 @@
 import android.util.AttributeSet;
 import android.util.Config;
 import android.util.Log;
-import java.util.ArrayList;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.concurrent.locks.ReentrantLock;
 import java.lang.ref.WeakReference;
 
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7897435..0095b91 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -51,7 +51,6 @@
 
     private static final String NO_STORE = "no-store";
     private static final String NO_CACHE = "no-cache";
-    private static final String PRIVATE  = "private";
     private static final String MAX_AGE = "max-age";
 
     private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
@@ -340,7 +339,7 @@
      * @hide - hide createCacheFile since it has a parameter of type headers, which is
      * in a hidden package.
      */
-    // can be called from any thread
+    // only called from WebCore thread
     public static CacheResult createCacheFile(String url, int statusCode,
             Headers headers, String mimeType, boolean forceCache) {
         if (!forceCache && mDisabled) {
@@ -349,17 +348,25 @@
 
         // according to the rfc 2616, the 303 response MUST NOT be cached.
         if (statusCode == 303) {
+            // remove the saved cache if there is any
+            mDataBase.removeCache(url);
             return null;
         }
 
         // like the other browsers, do not cache redirects containing a cookie
         // header.
         if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) {
+            // remove the saved cache if there is any
+            mDataBase.removeCache(url);
             return null;
         }
 
         CacheResult ret = parseHeaders(statusCode, headers, mimeType);
-        if (ret != null) {
+        if (ret == null) {
+            // this should only happen if the headers has "no-store" in the
+            // cache-control. remove the saved cache if there is any
+            mDataBase.removeCache(url);
+        } else {
             setupFiles(url, ret);
             try {
                 ret.outStream = new FileOutputStream(ret.outFile);
@@ -628,7 +635,7 @@
                 // must be re-validated on every load. It does not mean that
                 // the content can not be cached. set to expire 0 means it
                 // can only be used in CACHE_MODE_CACHE_ONLY case
-                if (NO_CACHE.equals(controls[i]) || PRIVATE.equals(controls[i])) {
+                if (NO_CACHE.equals(controls[i])) {
                     ret.expires = 0;
                 } else if (controls[i].startsWith(MAX_AGE)) {
                     int separator = controls[i].indexOf('=');
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index 8d66529..aa6c76b 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -24,30 +24,39 @@
 import java.util.Iterator;
 
 /**
- * The class CookieSyncManager is used to synchronize the browser cookies
- * between RAM and FLASH. To get the best performance, browser cookie is saved
- * in RAM. We use a separate thread to sync the cookies between RAM and FLASH on
- * a timer base.
+ * The CookieSyncManager is used to synchronize the browser cookie store
+ * between RAM and permanent storage. To get the best performance, browser cookies are
+ * saved in RAM. A separate thread saves the cookies between, driven by a timer.
  * <p>
+ *
  * To use the CookieSyncManager, the host application has to call the following
- * when the application starts.
+ * when the application starts:
  * <p>
- * CookieSyncManager.createInstance(context)
+ *
+ * <pre class="prettyprint">CookieSyncManager.createInstance(context)</pre><p>
+ *
+ * To set up for sync, the host application has to call<p>
+ * <pre class="prettyprint">CookieSyncManager.getInstance().startSync()</pre><p>
+ *
+ * in Activity.onResume(), and call
  * <p>
- * To set up for sync, the host application has to call
- * <p>
- * CookieSyncManager.getInstance().startSync()
- * <p>
- * in its Activity.onResume(), and call
- * <p>
+ *
+ * <pre class="prettyprint">
  * CookieSyncManager.getInstance().stopSync()
- * <p>
- * in its Activity.onStop().
- * <p>
+ * </pre><p>
+ *
+ * in Activity.onPause().<p>
+ *
  * To get instant sync instead of waiting for the timer to trigger, the host can
  * call
  * <p>
- * CookieSyncManager.getInstance().sync()
+ * <pre class="prettyprint">CookieSyncManager.getInstance().sync()</pre><p>
+ *
+ * The sync interval is 5 minutes, so you will want to force syncs
+ * manually anyway, for instance in {@link
+ * WebViewClient#onPageFinished}. Note that even sync() happens
+ * asynchronously, so don't do it just as your activity is shutting
+ * down.
  */
 public final class CookieSyncManager extends WebSyncManager {
 
@@ -90,7 +99,7 @@
     }
 
     /**
-     * Package level api, called from CookieManager Get all the cookies which
+     * Package level api, called from CookieManager. Get all the cookies which
      * matches a given base domain.
      * @param domain
      * @return A list of Cookie
diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java
index dcdc949..c1d1280 100644
--- a/core/java/android/webkit/DataLoader.java
+++ b/core/java/android/webkit/DataLoader.java
@@ -16,12 +16,10 @@
 
 package android.webkit;
 
-import org.apache.http.protocol.HTTP;
-
-import android.net.http.Headers;
-
 import java.io.ByteArrayInputStream;
 
+import org.apache.harmony.luni.util.Base64;
+
 /**
  * This class is a concrete implementation of StreamLoader that uses the
  * content supplied as a URL as the source for the stream. The mimetype
@@ -30,8 +28,6 @@
  */
 class DataLoader extends StreamLoader {
 
-    private String mContentType;  // Content mimetype, if supplied in URL
-
     /**
      * Constructor uses the dataURL as the source for an InputStream
      * @param dataUrl data: URL string optionally containing a mimetype
@@ -41,16 +37,20 @@
         super(loadListener);
 
         String url = dataUrl.substring("data:".length());
-        String content;
+        byte[] data = null;
         int commaIndex = url.indexOf(',');
         if (commaIndex != -1) {
-            mContentType = url.substring(0, commaIndex);
-            content = url.substring(commaIndex + 1);
+            String contentType = url.substring(0, commaIndex);
+            data = url.substring(commaIndex + 1).getBytes();
+            loadListener.parseContentTypeHeader(contentType);
+            if (loadListener.transferEncoding().equals("base64")) {
+                data = Base64.decode(data);
+            }
         } else {
-            content = url;
+            data = url.getBytes();
         }
-        mDataStream = new ByteArrayInputStream(content.getBytes());
-        mContentLength = content.length();
+        mDataStream = new ByteArrayInputStream(data);
+        mContentLength = data.length;
     }
 
     @Override
@@ -60,10 +60,7 @@
     }
 
     @Override
-    protected void buildHeaders(Headers headers) {
-        if (mContentType != null) {
-            headers.setContentType(mContentType);
-        }
+    protected void buildHeaders(android.net.http.Headers h) {
     }
 
     /**
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index c6ec2d2..48b2081 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -47,14 +47,16 @@
      * Wdy, DD Mon YYYY HH:MM:SS
      * Wdy Mon (SP)D HH:MM:SS YYYY
      * Wdy Mon DD HH:MM:SS YYYY GMT
+     * 
+     * HH can be H if the first digit is zero.
      */
     private static final String HTTP_DATE_RFC_REGEXP =
             "([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]"
-            + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])";
+            + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
 
     private static final String HTTP_DATE_ANSIC_REGEXP =
             "[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]"
-            + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
+            + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
 
     /**
      * The compiled version of the HTTP-date regular expressions.
@@ -65,6 +67,12 @@
             Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
 
     private static class TimeOfDay {
+        TimeOfDay(int h, int m, int s) {
+            this.hour = h;
+            this.minute = m;
+            this.second = s;
+        }
+        
         int hour;
         int minute;
         int second;
@@ -76,7 +84,7 @@
         int date = 1;
         int month = Calendar.JANUARY;
         int year = 1970;
-        TimeOfDay timeOfDay = new TimeOfDay();
+        TimeOfDay timeOfDay;
 
         Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
         if (rfcMatcher.find()) {
@@ -183,13 +191,22 @@
     }
 
     private static TimeOfDay getTime(String timeString) {
-        TimeOfDay time = new TimeOfDay();
-        time.hour = (timeString.charAt(0) - '0') * 10
-                + (timeString.charAt(1) - '0');
-        time.minute = (timeString.charAt(3) - '0') * 10
-                + (timeString.charAt(4) - '0');
-        time.second = (timeString.charAt(6) - '0') * 10
-                + (timeString.charAt(7) - '0');
-        return time;
+        // HH might be H
+        int i = 0;
+        int hour = timeString.charAt(i++) - '0';
+        if (timeString.charAt(i) != ':')
+            hour = hour * 10 + (timeString.charAt(i++) - '0');
+        // Skip ':'
+        i++;
+        
+        int minute = (timeString.charAt(i++) - '0') * 10
+                    + (timeString.charAt(i++) - '0');
+        // Skip ':'
+        i++;
+        
+        int second = (timeString.charAt(i++) - '0') * 10
+                  + (timeString.charAt(i++) - '0');
+
+        return new TimeOfDay(hour, minute, second);        
     }
 }
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 2a84683..1831c92 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -33,9 +33,13 @@
     // Instant timer is used to implement a timer that needs to fire almost
     // immediately.
     private boolean mHasInstantTimer;
+
     // Reference count the pause/resume of timers
     private int mPauseTimerRefCount;
 
+    private boolean mTimerPaused;
+    private boolean mHasDeferredTimers;
+
     /**
      * Construct a new JWebCoreJavaBridge to interface with
      * WebCore timers and cookies.
@@ -50,6 +54,17 @@
     }
 
     /**
+     * Call native timer callbacks.
+     */
+    private void fireSharedTimer() { 
+        PerfChecker checker = new PerfChecker();
+        // clear the flag so that sharedTimerFired() can set a new timer
+        mHasInstantTimer = false;
+        sharedTimerFired();
+        checker.responseAlert("sharedTimer");
+    }
+
+    /**
      * handleMessage
      * @param msg The dispatched message.
      *
@@ -59,11 +74,11 @@
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case TIMER_MESSAGE: {
-                PerfChecker checker = new PerfChecker();
-                // clear the flag so that sharedTimerFired() can set a new timer
-                mHasInstantTimer = false;
-                sharedTimerFired();
-                checker.responseAlert("sharedTimer");
+                if (mTimerPaused) {
+                    mHasDeferredTimers = true;
+                } else {
+                    fireSharedTimer();
+                }
                 break;
             }
             case FUNCPTR_MESSAGE:
@@ -85,7 +100,8 @@
      */
     public void pause() {
         if (--mPauseTimerRefCount == 0) {
-            setDeferringTimers(true);
+            mTimerPaused = true;
+            mHasDeferredTimers = false;
         }
     }
 
@@ -94,7 +110,11 @@
      */
     public void resume() {
         if (++mPauseTimerRefCount == 1) {
-            setDeferringTimers(false);
+           mTimerPaused = false;
+           if (mHasDeferredTimers) {
+               mHasDeferredTimers = false;
+               fireSharedTimer();
+           }
         }
     }
 
@@ -184,11 +204,11 @@
         }
         removeMessages(TIMER_MESSAGE);
         mHasInstantTimer = false;
+        mHasDeferredTimers = false;
     }
 
     private native void nativeConstructor();
     private native void nativeFinalize();
     private native void sharedTimerFired();
-    private native void setDeferringTimers(boolean defer);
     public native void setNetworkOnLine(boolean online);
 }
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index d583eb1..d3e26bd 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -43,8 +43,6 @@
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
-import org.apache.commons.codec.binary.Base64;
-
 class LoadListener extends Handler implements EventHandler {
 
     private static final String LOGTAG = "webkit";
@@ -140,8 +138,6 @@
         mBrowserFrame = frame;
         setUrl(url);
         mNativeLoader = nativeLoader;
-        mMimeType = "";
-        mEncoding = "";
         mSynchronous = synchronous;
         if (synchronous) {
             mMessageQueue = new Vector<Message>();
@@ -292,8 +288,6 @@
     private void handleHeaders(Headers headers) {
         if (mCancelled) return;
         mHeaders = headers;
-        mMimeType = "";
-        mEncoding = "";
 
         ArrayList<String> cookies = headers.getSetCookie();
         for (int i = 0; i < cookies.size(); ++i) {
@@ -313,24 +307,21 @@
 
             // If we have one of "generic" MIME types, try to deduce
             // the right MIME type from the file extension (if any):
-            if (mMimeType.equalsIgnoreCase("text/plain") ||
-                    mMimeType.equalsIgnoreCase("application/octet-stream")) {
+            if (mMimeType.equals("text/plain") ||
+                    mMimeType.equals("application/octet-stream")) {
 
                 String newMimeType = guessMimeTypeFromExtension();
                 if (newMimeType != null) {
                     mMimeType = newMimeType;
                 }
-            } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
+            } else if (mMimeType.equals("text/vnd.wap.wml")) {
                 // As we don't support wml, render it as plain text
                 mMimeType = "text/plain";
             } else {
-                // XXX: Until the servers send us either correct xhtml or
-                // text/html, treat application/xhtml+xml as text/html.
                 // It seems that xhtml+xml and vnd.wap.xhtml+xml mime
                 // subtypes are used interchangeably. So treat them the same.
-                if (mMimeType.equalsIgnoreCase("application/xhtml+xml") ||
-                        mMimeType.equals("application/vnd.wap.xhtml+xml")) {
-                    mMimeType = "text/html";
+                if (mMimeType.equals("application/vnd.wap.xhtml+xml")) {
+                    mMimeType = "application/xhtml+xml";
                 }
             }
         } else {
@@ -445,6 +436,9 @@
         status.put("reason", reasonPhrase);
         // New status means new data. Clear the old.
         mDataBuilder.clear();
+        mMimeType = "";
+        mEncoding = "";
+        mTransferEncoding = "";
         sendMessageInternal(obtainMessage(MSG_STATUS, status));
     }
 
@@ -520,19 +514,6 @@
             Log.v(LOGTAG, "LoadListener.data(): url: " + url());
         }
 
-        // Decode base64 data
-        // Note: It's fine that we only decode base64 here and not in the other
-        // data call because the only caller of the stream version is not
-        // base64 encoded.
-        if ("base64".equalsIgnoreCase(mTransferEncoding)) {
-            if (length < data.length) {
-                byte[] trimmedData = new byte[length];
-                System.arraycopy(data, 0, trimmedData, 0, length);
-                data = trimmedData;
-            }
-            data = Base64.decodeBase64(data);
-            length = data.length;
-        }
         // Synchronize on mData because commitLoad may write mData to WebCore
         // and we don't want to replace mData or mDataLength at the same time
         // as a write.
@@ -907,6 +888,10 @@
         return mMimeType;
     }
 
+    String transferEncoding() {
+        return mTransferEncoding;
+    }
+
     /*
      * Return the size of the content being downloaded. This represents the
      * full content size, even under the situation where the download has been
@@ -1201,7 +1186,7 @@
     private static final Pattern CONTENT_TYPE_PATTERN =
             Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
 
-    private void parseContentTypeHeader(String contentType) {
+    /* package */ void parseContentTypeHeader(String contentType) {
         if (WebView.LOGV_ENABLED) {
             Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
                     "contentType: " + contentType);
@@ -1223,13 +1208,14 @@
                     mEncoding = contentType.substring(i + 1);
                 }
                 // Trim excess whitespace.
-                mEncoding = mEncoding.trim();
+                mEncoding = mEncoding.trim().toLowerCase();
 
                 if (i < contentType.length() - 1) {
                     // for data: uri the mimeType and encoding have
                     // the form image/jpeg;base64 or text/plain;charset=utf-8
                     // or text/html;charset=utf-8;base64
-                    mTransferEncoding = contentType.substring(i + 1).trim();
+                    mTransferEncoding =
+                            contentType.substring(i + 1).trim().toLowerCase();
                 }
             } else {
                 mMimeType = contentType;
@@ -1249,6 +1235,8 @@
                 guessMimeType();
             }
         }
+        // Ensure mMimeType is lower case.
+        mMimeType = mMimeType.toLowerCase();
     }
 
     /**
@@ -1379,7 +1367,7 @@
             mMimeType = "text/html";
             String newMimeType = guessMimeTypeFromExtension();
             if (newMimeType != null) {
-                mMimeType =  newMimeType;
+                mMimeType = newMimeType;
             }
         }
     }
@@ -1393,19 +1381,8 @@
             Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
         }
 
-        String mimeType =
-                MimeTypeMap.getSingleton().getMimeTypeFromExtension(
-                        MimeTypeMap.getFileExtensionFromUrl(mUrl));
-
-        if (mimeType != null) {
-            // XXX: Until the servers send us either correct xhtml or
-            // text/html, treat application/xhtml+xml as text/html.
-            if (mimeType.equals("application/xhtml+xml")) {
-                mimeType = "text/html";
-            }
-        }
-
-        return mimeType;
+        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+                MimeTypeMap.getFileExtensionFromUrl(mUrl));
     }
 
     /**
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 85c2275..096f38a 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -358,6 +358,7 @@
             sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false);
             sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false);
             sMimeTypeMap.loadEntry("application/x-xfig", "fig", false);
+            sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml", false);
             sMimeTypeMap.loadEntry("audio/basic", "snd", false);
             sMimeTypeMap.loadEntry("audio/midi", "mid", false);
             sMimeTypeMap.loadEntry("audio/midi", "midi", false);
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index 705157c..7d6d7cc 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -102,7 +102,7 @@
                 // to pass data to the loader
                 mData = new byte[8192];
                 sendHeaders();
-                while (!sendData());
+                while (!sendData() && !mHandler.cancelled());
                 closeStreamAndSendEndData();
                 mHandler.loadSynchronousMessages();
             }
@@ -116,6 +116,10 @@
         if (WebView.DEBUG && mHandler.isSynchronous()) {
             throw new AssertionError();
         }
+        if (mHandler.cancelled()) {
+            closeStreamAndSendEndData();
+            return;
+        }
         switch(msg.what) {
             case MSG_STATUS:
                 if (setupStreamAndSendStatus()) {
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index 9de97c9..6fe64ee 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -17,19 +17,11 @@
 package android.webkit;
 
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.Selection;
 import android.text.Spannable;
-import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.method.MovementMethod;
 import android.view.inputmethod.EditorInfo;
@@ -86,32 +78,10 @@
     /* package */ TextDialog(Context context, WebView webView) {
         super(context);
         mWebView = webView;
-        ShapeDrawable background = new ShapeDrawable(new RectShape());
-        Paint shapePaint = background.getPaint();
-        shapePaint.setStyle(Paint.Style.STROKE);
-        ColorDrawable color = new ColorDrawable(Color.WHITE);
-        Drawable[] array = new Drawable[2];
-        array[0] = color;
-        array[1] = background;
-        LayerDrawable layers = new LayerDrawable(array);
-        // Hide WebCore's text behind this and allow the WebView
-        // to draw its own focusring.
-        setBackgroundDrawable(layers);
-        // Align the text better with the text behind it, so moving
-        // off of the textfield will not appear to move the text.
-        setPadding(3, 2, 0, 0);
         mMaxLength = -1;
-        // Turn on subpixel text, and turn off kerning, so it better matches
-        // the text in webkit.
-        TextPaint paint = getPaint();
-        int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
-                Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
-        paint.setFlags(flags);
-        // Set the text color to black, regardless of the theme.  This ensures
-        // that other applications that use embedded WebViews will properly
-        // display the text in textfields.
-        setTextColor(Color.BLACK);
         setImeOptions(EditorInfo.IME_ACTION_NONE);
+        // Allow webkit's drawing to show through
+        setWillNotDraw(true);
     }
 
     @Override
@@ -225,19 +195,21 @@
                     return true;
                 }
             }
+            /* FIXME:
+             * In theory, we would like to send the events for the arrow keys.
+             * However, the TextView can arbitrarily change the selection (i.e.
+             * long press followed by using the trackball).  Therefore, we keep
+             * in sync with the TextView via onSelectionChanged.  If we also
+             * send the DOM event, we lose the correct selection.
             if (isArrowKey) {
                 // Arrow key does not change the text, but we still want to send
                 // the DOM events.
                 sendDomEvent(event);
             }
+             */
             mScrollToAccommodateCursor = true;
             return true;
         }
-        // FIXME: TextViews return false for up and down key events even though
-        // they change the selection. Since we don't want the get out of sync
-        // with WebCore's notion of the current selection, reset the selection
-        // to what it was before the key event.
-        Selection.setSelection(text, oldStart, oldEnd);
         // Ignore the key up event for newlines. This prevents
         // multiple newlines in the native textarea.
         if (mGotEnterDown && !down) {
@@ -290,13 +262,12 @@
     }
 
     @Override
-    public boolean onPreDraw() {
-        if (getLayout() == null) {
-            measure(mWidthSpec, mHeightSpec);
+    protected void onSelectionChanged(int selStart, int selEnd) {
+        if (mWebView != null) {
+            mWebView.setSelection(selStart, selEnd);
         }
-        return super.onPreDraw();
     }
-    
+
     @Override
     protected void onTextChanged(CharSequence s,int start,int before,int count){
         super.onTextChanged(s, start, before, count);
@@ -341,18 +312,17 @@
             // trackball or auto-correct.
             mWebView.setSelection(start, start + before);
         }
-        updateCachedTextfield();
-        if (cannotUseKeyEvents) {
-            return;
-        }
-        int length = events.length;
-        for (int i = 0; i < length; i++) {
-            // We never send modifier keys to native code so don't send them
-            // here either.
-            if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
-                sendDomEvent(events[i]);
+        if (!cannotUseKeyEvents) {
+            int length = events.length;
+            for (int i = 0; i < length; i++) {
+                // We never send modifier keys to native code so don't send them
+                // here either.
+                if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
+                    sendDomEvent(events[i]);
+                }
             }
         }
+        updateCachedTextfield();
     }
     
     @Override
@@ -367,12 +337,7 @@
         MovementMethod move = getMovementMethod();
         if (move != null && getLayout() != null &&
             move.onTrackballEvent(this, text, event)) {
-            // Need to pass down the selection, which has changed.
-            // FIXME: This should work, but does not, so we set the selection
-            // in onTextChanged.
-            //int start = Selection.getSelectionStart(text);
-            //int end = Selection.getSelectionEnd(text);
-            //mWebView.setSelection(start, end);
+            // Selection is changed in onSelectionChanged
             return true;
         }
         // If the user is in a textfield, and the movement method is not
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 105eacd..98e66b6 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -111,9 +111,13 @@
     private boolean mSyncPending = false;
     // Custom handler that queues messages until the WebCore thread is active.
     private final EventHandler mEventHandler;
+
     // Private settings so we don't have to go into native code to
     // retrieve the values. After setXXX, postSync() needs to be called.
-    // XXX: The default values need to match those in WebSettings.cpp
+    //
+    // The default values need to match those in WebSettings.cpp
+    // If the defaults change, please also update the JavaDocs so developers
+    // know what they are.
     private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
     private Context         mContext;
     private TextSize        mTextSize = TextSize.NORMAL;
@@ -155,6 +159,8 @@
     private boolean         mSupportZoom = true;
     private boolean         mBuiltInZoomControls = false;
     private boolean         mAllowFileAccess = true;
+    private String          mAppCachePath = "";
+    private boolean         mAppCacheEnabled = false;
 
     // Class to handle messages before WebCore is ready.
     private class EventHandler {
@@ -459,24 +465,21 @@
     }
 
     /**
-     * Tell the WebView to use the double tree rendering algorithm.
-     * @param use True if the WebView is to use double tree rendering, false
-     *            otherwise.
+     * @deprecated This setting controlled a rendering optimization
+     * that is no longer present. Setting it now has no effect.
      */
+    @Deprecated
     public synchronized void setUseDoubleTree(boolean use) {
-        if (mUseDoubleTree != use) {
-            mUseDoubleTree = use;
-            postSync();
-        }
+        return;
     }
 
     /**
-     * Return true if the WebView is using the double tree rendering algorithm.
-     * @return True if the WebView is using the double tree rendering
-     *         algorithm.
+     * @deprecated This setting controlled a rendering optimization
+     * that is no longer present. Setting it now has no effect.
      */
+    @Deprecated
     public synchronized boolean getUseDoubleTree() {
-        return mUseDoubleTree;
+        return false;
     }
 
     /**
@@ -581,7 +584,7 @@
     }
 
     /**
-     * Return the current layout algorithm.
+     * Return the current layout algorithm. The default is NARROW_COLUMNS.
      * @return LayoutAlgorithm enum value describing the layout algorithm
      *         being used.
      * @see WebSettings.LayoutAlgorithm
@@ -602,7 +605,7 @@
     }
 
     /**
-     * Get the standard font family name.
+     * Get the standard font family name. The default is "sans-serif".
      * @return The standard font family name as a string.
      */
     public synchronized String getStandardFontFamily() {
@@ -621,7 +624,7 @@
     }
 
     /**
-     * Get the fixed font family name.
+     * Get the fixed font family name. The default is "monospace".
      * @return The fixed font family name as a string.
      */
     public synchronized String getFixedFontFamily() {
@@ -648,7 +651,7 @@
     }
 
     /**
-     * Set the serif font family name.
+     * Set the serif font family name. The default is "sans-serif".
      * @param font A font family name.
      */
     public synchronized void setSerifFontFamily(String font) {
@@ -659,7 +662,7 @@
     }
 
     /**
-     * Get the serif font family name.
+     * Get the serif font family name. The default is "serif".
      * @return The serif font family name as a string.
      */
     public synchronized String getSerifFontFamily() {
@@ -678,7 +681,7 @@
     }
 
     /**
-     * Get the cursive font family name.
+     * Get the cursive font family name. The default is "cursive".
      * @return The cursive font family name as a string.
      */
     public synchronized String getCursiveFontFamily() {
@@ -697,7 +700,7 @@
     }
 
     /**
-     * Get the fantasy font family name.
+     * Get the fantasy font family name. The default is "fantasy".
      * @return The fantasy font family name as a string.
      */
     public synchronized String getFantasyFontFamily() {
@@ -718,7 +721,7 @@
     }
 
     /**
-     * Get the minimum font size.
+     * Get the minimum font size. The default is 8.
      * @return A non-negative integer between 1 and 72.
      */
     public synchronized int getMinimumFontSize() {
@@ -739,7 +742,7 @@
     }
 
     /**
-     * Get the minimum logical font size.
+     * Get the minimum logical font size. The default is 8.
      * @return A non-negative integer between 1 and 72.
      */
     public synchronized int getMinimumLogicalFontSize() {
@@ -760,7 +763,7 @@
     }
 
     /**
-     * Get the default font size.
+     * Get the default font size. The default is 16.
      * @return A non-negative integer between 1 and 72.
      */
     public synchronized int getDefaultFontSize() {
@@ -781,7 +784,7 @@
     }
 
     /**
-     * Get the default fixed font size.
+     * Get the default fixed font size. The default is 16.
      * @return A non-negative integer between 1 and 72.
      */
     public synchronized int getDefaultFixedFontSize() {
@@ -801,6 +804,7 @@
 
     /**
      * Return true if the WebView will load image resources automatically.
+     * The default is true.
      * @return True if the WebView loads images automatically.
      */
     public synchronized boolean getLoadsImagesAutomatically() {
@@ -820,16 +824,16 @@
     }
 
     /**
-     * Return true if the WebView will block network image.
+     * Return true if the WebView will block network image. The default is false.
      * @return True if the WebView blocks network image.
      */
     public synchronized boolean getBlockNetworkImage() {
         return mBlockNetworkImage;
     }
-    
+
     /**
      * @hide
-     * Tell the WebView to block all network load requests. 
+     * Tell the WebView to block all network load requests.
      * @param flag True if the WebView should block all network loads
      */
     public synchronized void setBlockNetworkLoads(boolean flag) {
@@ -842,13 +846,14 @@
     /**
      * @hide
      * Return true if the WebView will block all network loads.
+     * The default is false.
      * @return True if the WebView blocks all network loads.
      */
     public synchronized boolean getBlockNetworkLoads() {
         return mBlockNetworkLoads;
     }
-    
-    
+
+
     private void verifyNetworkAccess() {
         if (!mBlockNetworkLoads) {
             if (mContext.checkPermission("android.permission.INTERNET", 
@@ -896,7 +901,34 @@
     }
 
     /**
-     * Return true if javascript is enabled.
+     * Tell the WebView to enable Application Caches API.
+     * @param flag True if the WebView should enable Application Caches.
+     * @hide pending api council approval
+     */
+    public synchronized void setAppCacheEnabled(boolean flag) {
+        if (mAppCacheEnabled != flag) {
+            mAppCacheEnabled = flag;
+            postSync();
+        }
+    }
+
+    /**
+     * Set a custom path to the Application Caches files. The client
+     * must ensure it exists before this call.
+     * @param appCachePath String path to the directory containing Application
+     * Caches files. The appCache path can be the empty string but should not
+     * be null. Passing null for this parameter will result in a no-op.
+     * @hide pending api council approval
+     */
+    public synchronized void setAppCachePath(String appCachePath) {
+        if (appCachePath != null && !appCachePath.equals(mAppCachePath)) {
+            mAppCachePath = appCachePath;
+            postSync();
+        }
+    }
+
+    /**
+     * Return true if javascript is enabled. <b>Note: The default is false.</b>
      * @return True if javascript is enabled.
      */
     public synchronized boolean getJavaScriptEnabled() {
@@ -933,7 +965,8 @@
     }
 
     /**
-     * Return true if javascript can open windows automatically.
+     * Return true if javascript can open windows automatically. The default
+     * is false.
      * @return True if javascript can open windows automatically during
      *         window.open().
      */
@@ -953,7 +986,7 @@
     }
 
     /**
-     * Get the default text encoding name.
+     * Get the default text encoding name. The default is "Latin-1".
      * @return The default text encoding name as a string.
      */
     public synchronized String getDefaultTextEncodingName() {
@@ -1042,8 +1075,8 @@
 
     /**
      * Set the priority of the Render thread. Unlike the other settings, this
-     * one only needs to be called once per process.
-     * 
+     * one only needs to be called once per process. The default is NORMAL.
+     *
      * @param priority RenderPriority, can be normal, high or low.
      */
     public synchronized void setRenderPriority(RenderPriority priority) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a926355..935e928 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -94,7 +94,104 @@
  * in a WebView, you must add the <var>INTERNET</var> permissions to your 
  * Android Manifest file:</p>
  * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
+ *
  * <p>This must be a child of the <code>&lt;manifest></code> element.</p>
+ *
+ * <h3>Basic usage</h3>
+ *
+ * <p>By default, a WebView provides no browser-like widgets, does not
+ * enable JavaScript and errors will be ignored. If your goal is only
+ * to display some HTML as a part of your UI, this is probably fine;
+ * the user won't need to interact with the web page beyond reading
+ * it, and the web page won't need to interact with the user. If you
+ * actually want a fully blown web browser, then you probably want to
+ * invoke the Browser application with your URL rather than show it
+ * with a WebView. See {@link android.content.Intent} for more information.</p>
+ *
+ * <pre class="prettyprint">
+ * WebView webview = new WebView(this);
+ * setContentView(webview);
+ *
+ * // Simplest usage: note that an exception will NOT be thrown
+ * // if there is an error loading this page (see below).
+ * webview.loadUrl("http://slashdot.org/");
+ *
+ * // Of course you can also load from any string:
+ * String summary = "&lt;html>&lt;body>You scored &lt;b>192</b> points.&lt;/body>&lt;/html>";
+ * webview.loadData(summary, "text/html", "utf-8");
+ * // ... although note that there are restrictions on what this HTML can do.
+ * // See the JavaDocs for loadData and loadDataWithBaseUrl for more info.
+ * </pre>
+ *
+ * <p>A WebView has several customization points where you can add your
+ * own behavior. These are:</p>
+ *
+ * <ul>
+ *   <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
+ *       This class is called when something that might impact a
+ *       browser UI happens, for instance, progress updates and
+ *       JavaScript alerts are sent here.
+ *   </li>
+ *   <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
+ *       It will be called when things happen that impact the
+ *       rendering of the content, eg, errors or form submissions. You
+ *       can also intercept URL loading here.</li>
+ *   <li>Via the {@link android.webkit.WebSettings} class, which contains
+ *       miscellaneous configuration. </li>
+ *   <li>With the {@link android.webkit.WebView#addJavascriptInterface} method.
+ *       This lets you bind Java objects into the WebView so they can be
+ *       controlled from the web pages JavaScript.</li>
+ * </ul>
+ *
+ * <p>Here's a more complicated example, showing error handling,
+ *    settings, and progress notification:</p>
+ *
+ * <pre class="prettyprint">
+ * // Let's display the progress in the activity title bar, like the
+ * // browser app does.
+ * getWindow().requestFeature(Window.FEATURE_PROGRESS);
+ *
+ * webview.getSettings().setJavaScriptEnabled(true);
+ *
+ * final Activity activity = this;
+ * webview.setWebChromeClient(new WebChromeClient() {
+ *   public void onProgressChanged(WebView view, int progress) {
+ *     // Activities and WebViews measure progress with different scales.
+ *     // The progress meter will automatically disappear when we reach 100%
+ *     activity.setProgress(progress * 1000);
+ *   }
+ * });
+ * webview.setWebViewClient(new WebViewClient() {
+ *   public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ *     Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
+ *   }
+ * });
+ *
+ * webview.loadUrl("http://slashdot.org/");
+ * </pre>
+ *
+ * <h3>Cookie and window management</h3>
+ *
+ * <p>For obvious security reasons, your application has its own
+ * cache, cookie store etc - it does not share the Browser
+ * applications data. Cookies are managed on a separate thread, so
+ * operations like index building don't block the UI
+ * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
+ * if you want to use cookies in your application.
+ * </p>
+ *
+ * <p>By default, requests by the HTML to open new windows are
+ * ignored. This is true whether they be opened by JavaScript or by
+ * the target attribute on a link. You can customize your
+ * WebChromeClient to provide your own behaviour for opening multiple windows,
+ * and render them in whatever manner you want.</p>
+ *
+ * <p>Standard behavior for an Activity is to be destroyed and
+ * recreated when the devices orientation is changed. This will cause
+ * the WebView to reload the current page. If you don't want that, you
+ * can set your Activity to handle the orientation and keyboardHidden
+ * changes, and then just leave the WebView alone. It'll automatically
+ * re-orient itself as appropriate.</p>
  */
 public class WebView extends AbsoluteLayout 
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
@@ -1831,14 +1928,15 @@
     }
 
     /**
-     * Clear the resource cache. This will cause resources to be re-downloaded
-     * if accessed again.
-     * <p>
-     * Note: this really needs to be a static method as it clears cache for all
-     * WebView. But we need mWebViewCore to send message to WebCore thread, so
-     * we can't make this static.
+     * Clear the resource cache. Note that the cache is per-application, so
+     * this will clear the cache for all WebViews used.
+     *
+     * @param includeDiskFiles If false, only the RAM cache is cleared.
      */
     public void clearCache(boolean includeDiskFiles) {
+        // Note: this really needs to be a static method as it clears cache for all
+        // WebView. But we need mWebViewCore to send message to WebCore thread, so
+        // we can't make this static.
         mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
                 includeDiskFiles ? 1 : 0, 0);
     }
@@ -2746,7 +2844,7 @@
     // Should only be called in UI thread
     void switchOutDrawHistory() {
         if (null == mWebViewCore) return; // CallbackProxy may trigger this
-        if (mDrawHistory) {
+        if (mDrawHistory && mWebViewCore.pictureReady()) {
             mDrawHistory = false;
             invalidate();
             int oldScrollX = mScrollX;
@@ -2861,19 +2959,16 @@
     }
 
     private void updateTextEntry() {
-        if (mTextEntry == null) {
-            mTextEntry = new TextDialog(mContext, WebView.this);
-            // Initialize our generation number.
-            mTextGeneration = 0;
-        }
         // If we do not have focus, do nothing until we gain focus.
-        if (!hasFocus() && !mTextEntry.hasFocus()
+        if (!hasFocus() && (null == mTextEntry || !mTextEntry.hasFocus())
                 || (mTouchMode >= FIRST_SCROLL_ZOOM 
                 && mTouchMode <= LAST_SCROLL_ZOOM)) {
             mNeedsUpdateTextEntry = true;
             return;
         }
         boolean alreadyThere = inEditingMode();
+        // inEditingMode can only return true if mTextEntry is non-null,
+        // so we can safely call remove() if (alreadyThere)
         if (0 == mNativeClass || !nativeUpdateFocusNode()) {
             if (alreadyThere) {
                 mTextEntry.remove();
@@ -2887,6 +2982,13 @@
             }
             return;
         }
+        // At this point, we know we have found an input field, so go ahead
+        // and create the TextDialog if necessary.
+        if (mTextEntry == null) {
+            mTextEntry = new TextDialog(mContext, WebView.this);
+            // Initialize our generation number.
+            mTextGeneration = 0;
+        }
         mTextEntry.setTextSize(contentToView(node.mTextSize));
         Rect visibleRect = sendOurVisibleRect();
         // Note that sendOurVisibleRect calls viewToContent, so the coordinates
@@ -3082,6 +3184,15 @@
             return false;
         }
 
+        if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
+                && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) {
+            // turn off copy select if a shift-key combo is pressed
+            mExtendSelection = mShiftIsPressed = false;
+            if (mTouchMode == TOUCH_SELECT_MODE) {
+                mTouchMode = TOUCH_INIT_MODE;
+            }
+        }
+
         if (getSettings().getNavDump()) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_4:
@@ -3331,6 +3442,7 @@
                 if (mNativeClass != 0) {
                     nativeRecordButtons(true, false, true);
                 }
+                setFocusControllerActive(true);
             } else {
                 // If our window gained focus, but we do not have it, do not
                 // draw the focus ring.
@@ -3356,11 +3468,22 @@
             if (mNativeClass != 0) {
                 nativeRecordButtons(false, false, true);
             }
+            setFocusControllerActive(false);
         }
         invalidate();
         super.onWindowFocusChanged(hasWindowFocus);
     }
 
+    /*
+     * Pass a message to WebCore Thread, determining whether the WebCore::Page's
+     * FocusController is "active" so that it will draw the blinking cursor.
+     */
+    private void setFocusControllerActive(boolean active) {
+        if (mWebViewCore != null) {
+            mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0);
+        }
+    }
+
     @Override
     protected void onFocusChanged(boolean focused, int direction,
             Rect previouslyFocusedRect) {
@@ -3379,6 +3502,10 @@
                 if (mNativeClass != 0) {
                     nativeRecordButtons(true, false, true);
                 }
+                // FIXME: This is unnecessary if we are gaining focus from the
+                // TextDialog.  How can we tell if it was the last thing in
+                // focus?
+                setFocusControllerActive(true);
             //} else {
                 // The WebView has gained focus while we do not have
                 // windowfocus.  When our window lost focus, we should have
@@ -3392,6 +3519,7 @@
                 if (mNativeClass != 0) {
                     nativeRecordButtons(false, false, true);
                 }
+                setFocusControllerActive(false);
             }
             mGotKeyDown = false;
         }
@@ -3603,9 +3731,6 @@
                     WebViewCore.pauseUpdate(mWebViewCore);
                     int contentX = viewToContent((int) x + mScrollX);
                     int contentY = viewToContent((int) y + mScrollY);
-                    if (inEditingMode()) {
-                        mTextEntry.updateCachedTextfield();
-                    }
                     nativeClearFocus(contentX, contentY);
                     // remove the zoom anchor if there is any
                     if (mZoomScale != 0) {
@@ -3783,9 +3908,6 @@
                 mTouchMode = TOUCH_DONE_MODE;
                 int contentX = viewToContent((int) mLastTouchX + mScrollX);
                 int contentY = viewToContent((int) mLastTouchY + mScrollY);
-                if (inEditingMode()) {
-                    mTextEntry.updateCachedTextfield();
-                }
                 nativeClearFocus(contentX, contentY);
                 break;
             }
@@ -4272,10 +4394,6 @@
         int contentY = viewToContent((int) mLastTouchY + mScrollY);
         Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
                 contentX + mNavSlop, contentY + mNavSlop);
-        // If we were already focused on a textfield, update its cache.
-        if (inEditingMode()) {
-            mTextEntry.updateCachedTextfield();
-        }
         nativeSelectBestAt(rect);
     }
 
@@ -4411,14 +4529,19 @@
 
         int scrollYDelta = 0;
 
-        if (rect.bottom > screenBottom && rect.top > screenTop) {
-            if (rect.height() > height) {
-                scrollYDelta += (rect.top - screenTop);
+        if (rect.bottom > screenBottom) {
+            int oneThirdOfScreenHeight = height / 3;
+            if (rect.height() > 2 * oneThirdOfScreenHeight) {
+                // If the rectangle is too tall to fit in the bottom two thirds
+                // of the screen, place it at the top.
+                scrollYDelta = rect.top - screenTop;
             } else {
-                scrollYDelta += (rect.bottom - screenBottom);
+                // If the rectangle will still fit on screen, we want its
+                // top to be in the top third of the screen.
+                scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
             }
         } else if (rect.top < screenTop) {
-            scrollYDelta -= (screenTop - rect.top);
+            scrollYDelta = rect.top - screenTop;
         }
 
         int width = getWidth() - getVerticalScrollbarWidth();
@@ -4654,6 +4777,7 @@
                     if (mInitialScale > 0) {
                         scale = mInitialScale / 100.0f;
                     } else  {
+                        if (initialScale < 0) break;
                         if (mWebViewCore.getSettings().getUseWideViewPort()) {
                             // force viewSizeChanged by setting mLastWidthSent
                             // to 0
@@ -4890,7 +5014,12 @@
                                 adapter.getCount(), 0,
                                 listView.getCheckedItemPositions());
                     }});
-                b.setNegativeButton(android.R.string.cancel, null);
+                b.setNegativeButton(android.R.string.cancel,
+                        new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        mWebViewCore.sendMessage(
+                                EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
+                }});
             }
             final AlertDialog dialog = b.create();
             listView.setAdapter(adapter);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 58d8ae7..1415597 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -285,6 +285,11 @@
      * split into parts. Called from the UI thread.
      */
     private native boolean nativeDrawContent(Canvas canvas, int color);
+
+    /**
+     * check to see if picture is blank and in progress
+     */
+    private native boolean nativePictureReady();
     
     /**
      * Redraw a portion of the picture set. The Point wh returns the
@@ -329,6 +334,8 @@
             String currentText, int keyCode, int keyValue, boolean down,
             boolean cap, boolean fn, boolean sym);
 
+    private native void nativeSetFocusControllerActive(boolean active);
+
     private native void nativeSaveDocumentState(int frame);
 
     private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
@@ -526,7 +533,7 @@
             "DELETE_SELECTION", // = 122;
             "LISTBOX_CHOICES", // = 123;
             "SINGLE_LISTBOX_CHOICE", // = 124;
-            "125",
+            "MESSAGE_RELAY", // = 125;
             "SET_BACKGROUND_COLOR", // = 126;
             "UNBLOCK_FOCUS", // = 127;
             "SAVE_DOCUMENT_STATE", // = 128;
@@ -543,6 +550,7 @@
             "LOAD_DATA", // = 139;
             "TOUCH_UP", // = 140;
             "TOUCH_EVENT", // = 141;
+            "SET_ACTIVE", // = 142;
         };
 
     class EventHub {
@@ -572,6 +580,7 @@
         static final int DELETE_SELECTION = 122;
         static final int LISTBOX_CHOICES = 123;
         static final int SINGLE_LISTBOX_CHOICE = 124;
+        static final int MESSAGE_RELAY = 125;
         static final int SET_BACKGROUND_COLOR = 126;
         static final int UNBLOCK_FOCUS = 127;
         static final int SAVE_DOCUMENT_STATE = 128;
@@ -594,6 +603,10 @@
         // message used to pass UI touch events to WebCore
         static final int TOUCH_EVENT = 141;
 
+        // Used to tell the focus controller whether to draw the blinking cursor
+        // or not, based on whether the WebView has focus.
+        static final int SET_ACTIVE = 142;
+
         // Network-based messaging
         static final int CLEAR_SSL_PREF_TABLE = 150;
 
@@ -642,7 +655,7 @@
                 public void handleMessage(Message msg) {
                     if (LOGV_ENABLED) {
                         Log.v(LOGTAG, msg.what < LOAD_URL || msg.what 
-                                > TOUCH_EVENT ? Integer.toString(msg.what)
+                                > SET_ACTIVE ? Integer.toString(msg.what)
                                 : HandlerDebugString[msg.what - LOAD_URL]);
                     }
                     switch (msg.what) {
@@ -864,6 +877,10 @@
                             break;
                         }
 
+                        case SET_ACTIVE:
+                            nativeSetFocusControllerActive(msg.arg1 == 1);
+                            break;
+
                         case ADD_JS_INTERFACE:
                             HashMap map = (HashMap) msg.obj;
                             Object obj = map.get("object");
@@ -1004,6 +1021,12 @@
                             // (See public method WebView.clearView)
                             nativeClearContent();
                             break;
+
+                        case MESSAGE_RELAY:
+                            if (msg.obj instanceof Message) {
+                                ((Message) msg.obj).sendToTarget();
+                            }
+                            break;
                     }
                 }
             };
@@ -1329,6 +1352,10 @@
         }
     }
 
+    /* package */ boolean pictureReady() {
+        return nativePictureReady();
+    }
+
     /*package*/ Picture copyContentPicture() {
         Picture result = new Picture();
         nativeCopyContentToPicture(result);
@@ -1421,9 +1448,14 @@
             return;
         }
         if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                    WebView.SCROLL_BY_MSG_ID, dx, dy, 
-                    new Boolean(animate)).sendToTarget();
+            Message msg = Message.obtain(mWebView.mPrivateHandler,
+                    WebView.SCROLL_BY_MSG_ID, dx, dy, new Boolean(animate));
+            if (mDrawIsScheduled) {
+                mEventHub.sendMessage(Message.obtain(null,
+                        EventHub.MESSAGE_RELAY, msg));
+            } else {
+                msg.sendToTarget();
+            }
         }
     }
 
@@ -1440,8 +1472,14 @@
             return;
         }
         if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                    WebView.SCROLL_TO_MSG_ID, x, y).sendToTarget();
+            Message msg = Message.obtain(mWebView.mPrivateHandler,
+                    WebView.SCROLL_TO_MSG_ID, x, y);
+            if (mDrawIsScheduled) {
+                mEventHub.sendMessage(Message.obtain(null,
+                        EventHub.MESSAGE_RELAY, msg));
+            } else {
+                msg.sendToTarget();
+            }
         }
     }
 
@@ -1458,8 +1496,14 @@
             return;
         }
         if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                    WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
+            Message msg = Message.obtain(mWebView.mPrivateHandler,
+                    WebView.SPAWN_SCROLL_TO_MSG_ID, x, y);
+            if (mDrawIsScheduled) {
+                mEventHub.sendMessage(Message.obtain(null,
+                        EventHub.MESSAGE_RELAY, msg));
+            } else {
+                msg.sendToTarget();
+            }
         }
     }
 
@@ -1517,7 +1561,7 @@
     private native void setViewportSettingsFromNative();
     
     // called by JNI
-    private void didFirstLayout() {
+    private void didFirstLayout(boolean standardLoad) {
         // Trick to ensure that the Picture has the exact height for the content
         // by forcing to layout with 0 height after the page is ready, which is
         // indicated by didFirstLayout. This is essential to get rid of the 
@@ -1583,16 +1627,14 @@
                         scaleLimit).sendToTarget();
                 mRestoredScale = 0;
             } else {
+                // if standardLoad is true, use mViewportInitialScale, otherwise
+                // pass -1 to the WebView to indicate no change of the scale.
                 Message.obtain(mWebView.mPrivateHandler,
-                        WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
+                        WebView.DID_FIRST_LAYOUT_MSG_ID,
+                        standardLoad ? mViewportInitialScale : -1,
                         mViewportWidth, scaleLimit).sendToTarget();
             }
 
-            // if no restored offset, move the new page to (0, 0)
-            Message.obtain(mWebView.mPrivateHandler, WebView.SCROLL_TO_MSG_ID,
-                    mRestoredX, mRestoredY).sendToTarget();
-            mRestoredX = mRestoredY = 0;
-
             // force an early draw for quick feedback after the first layout
             if (mCurrentViewWidth != 0) {
                 synchronized (this) {
@@ -1600,10 +1642,19 @@
                         mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
                     }
                     mDrawIsScheduled = true;
+                    // if no restored offset, move the new page to (0, 0)
+                    mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
+                            EventHub.MESSAGE_RELAY, Message.obtain(
+                                    mWebView.mPrivateHandler,
+                                    WebView.SCROLL_TO_MSG_ID, mRestoredX,
+                                    mRestoredY)));
                     mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
                             EventHub.WEBKIT_DRAW));
                 }
             }
+
+            // reset restored offset
+            mRestoredX = mRestoredY = 0;
         }
     }
 
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 04cb8a0..f92eb99 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -320,11 +320,6 @@
         
         final int max = getMax();
         progress += scale * max;
-        if (progress < 0) {
-            progress = 0;
-        } else if (progress > max) {
-            progress = max;
-        }
         
         setProgress((int) progress, true);
     }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 1e122a7..f999045 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -283,6 +283,80 @@
         mDropDownAnchorId = id;
         mDropDownAnchorView = null;
     }
+<<<<<<< HEAD:core/java/android/widget/AutoCompleteTextView.java
+    
+    /**
+     * <p>Gets the background of the auto-complete drop-down list.</p>
+     * 
+     * @return the background drawable
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     */
+    public Drawable getDropDownBackground() {
+        return mPopup.getBackground();
+    }
+    
+    /**
+     * <p>Sets the background of the auto-complete drop-down list.</p>
+     * 
+     * @param d the drawable to set as the background
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     */
+    public void setDropDownBackgroundDrawable(Drawable d) {
+        mPopup.setBackgroundDrawable(d);
+    }
+    
+    /**
+     * <p>Sets the background of the auto-complete drop-down list.</p>
+     * 
+     * @param id the id of the drawable to set as the background
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     */
+    public void setDropDownBackgroundResource(int id) {
+        mPopup.setBackgroundDrawable(getResources().getDrawable(id));
+    }
+    
+    /**
+     * <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
+     * 
+     * @param offset the vertical offset
+     */
+    public void setDropDownVerticalOffset(int offset) {
+        mDropDownVerticalOffset = offset;
+    }
+    
+    /**
+     * <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
+     * 
+     * @return the vertical offset
+     */
+    public int getDropDownVerticalOffset() {
+        return mDropDownVerticalOffset;
+    }
+    
+    /**
+     * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
+     * 
+     * @param offset the horizontal offset
+     */
+    public void setDropDownHorizontalOffset(int offset) {
+        mDropDownHorizontalOffset = offset;
+    }
+    
+    /**
+     * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
+     * 
+     * @return the horizontal offset
+     */
+    public int getDropDownHorizontalOffset() {
+        return mDropDownHorizontalOffset;
+    }
+	
+|||||||
+
+=======
     
     /**
      * <p>Gets the background of the auto-complete drop-down list.</p>
@@ -339,6 +413,7 @@
         mPopup.setAnimationStyle(animationStyle);
     }
 
+>>>>>>> f3ccf8a5a5a3f6e46781538358bddca992a70e3d:core/java/android/widget/AutoCompleteTextView.java
     /**
      * <p>Returns the animation style that is used when the drop-down list appears and disappears
      * </p>
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ac8b589..fa2bb22 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -93,7 +93,26 @@
 
     /** Controls whether we should preload resources during zygote init. */
     private static final boolean PRELOAD_RESOURCES = true;
-    
+
+    /**
+     * List of methods we "warm up" in the register map cache.  These were
+     * chosen because they appeared on the stack in GCs in multiple
+     * applications.
+     *
+     * This is in a VM-ready format, to minimize string processing.  If a
+     * class is not already loaded, or a method is not found, the entry
+     * will be skipped.
+     *
+     * This doesn't really merit a separately-generated input file at this
+     * time.  The list is fairly short, and the consequences of failure
+     * are minor.
+     */
+    private static final String[] REGISTER_MAP_METHODS = {
+        // (currently not doing any)
+        //"Landroid/app/Activity;.setContentView:(I)V",
+    };
+
+
     /**
      * Invokes a static "main(argv[]) method on class "className".
      * Converts various failing exceptions into RuntimeExceptions, with
@@ -319,6 +338,45 @@
     }
 
     /**
+     * Pre-caches register maps for methods that are commonly used.
+     */
+    private static void cacheRegisterMaps() {
+        String failed = null;
+        int failure;
+        long startTime = System.nanoTime();
+
+        failure = 0;
+
+        for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) {
+            String str = REGISTER_MAP_METHODS[i];
+
+            if (!Debug.cacheRegisterMap(str)) {
+                if (failed == null)
+                    failed = str;
+                failure++;
+            }
+        }
+
+        long delta = System.nanoTime() - startTime;
+
+        if (failure == REGISTER_MAP_METHODS.length) {
+            if (REGISTER_MAP_METHODS.length > 0) {
+                Log.i(TAG,
+                    "Register map caching failed (precise GC not enabled?)");
+            }
+            return;
+        }
+
+        Log.i(TAG, "Register map cache: found " +
+            (REGISTER_MAP_METHODS.length - failure) + " of " +
+            REGISTER_MAP_METHODS.length + " methods in " +
+            (delta / 1000000L) + "ms");
+        if (failure > 0) {
+            Log.i(TAG, "  First failure: " + failed);
+        }
+    }
+
+    /**
      * Load in commonly used resources, so they can be shared across
      * processes.
      *
@@ -510,6 +568,7 @@
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                 SystemClock.uptimeMillis());
             preloadClasses();
+            //cacheRegisterMaps();
             preloadResources();
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                 SystemClock.uptimeMillis());
diff --git a/core/java/com/google/android/mms/pdu/EncodedStringValue.java b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
index 7696c5e..a27962d 100644
--- a/core/java/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
@@ -269,4 +269,16 @@
 
         return new EncodedStringValue(value.mCharacterSet, value.mData);
     }
+    
+    public static EncodedStringValue[] encodeStrings(String[] array) {
+        int count = array.length;
+        if (count > 0) {
+            EncodedStringValue[] encodedArray = new EncodedStringValue[count];
+            for (int i = 0; i < count; i++) {
+                encodedArray[i] = new EncodedStringValue(array[i]);
+            }
+            return encodedArray;
+        }
+        return null;
+    }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ac35459..de64e84 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -38,7 +38,6 @@
 	android_text_AndroidCharacter.cpp \
 	android_text_KeyCharacterMap.cpp \
 	android_os_Debug.cpp \
-	android_os_Exec.cpp \
 	android_os_FileUtils.cpp \
 	android_os_MemoryFile.cpp \
 	android_os_ParcelFileDescriptor.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7c9f457..422020e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -130,7 +130,6 @@
 extern int register_android_os_StatFs(JNIEnv *env);
 extern int register_android_os_SystemProperties(JNIEnv *env);
 extern int register_android_os_Hardware(JNIEnv* env);
-extern int register_android_os_Exec(JNIEnv *env);
 extern int register_android_os_SystemClock(JNIEnv* env);
 extern int register_android_os_FileObserver(JNIEnv *env);
 extern int register_android_os_FileUtils(JNIEnv *env);
@@ -505,11 +504,17 @@
     //LOGD("language=%s region=%s\n", language, region);
 }
 
-void AndroidRuntime::start(const char* className, const bool startSystemServer)
+/*
+ * Start the Dalvik Virtual Machine.
+ *
+ * Various arguments, most determined by system properties, are passed in.
+ * The "mOptions" vector is updated.
+ *
+ * Returns 0 on success.
+ */
+int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
 {
-    LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
-
-    JNIEnv* env;
+    int result = -1;
     JavaVMInitArgs initArgs;
     JavaVMOption opt;
     char propBuf[PROPERTY_VALUE_MAX];
@@ -518,24 +523,11 @@
     char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
-    char* slashClassName = NULL;
-    char* cp;
     bool checkJni = false;
+    bool checkDexSum = false;
     bool logStdio = false;
     enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
 
-    blockSigpipe();
-
-    /* 
-     * 'startSystemServer == true' means runtime is obslete and not run from 
-     * init.rc anymore, so we print out the boot start event here.
-     */
-    if (startSystemServer) {
-        /* track our progress through the boot sequence */
-        const int LOG_BOOT_PROGRESS_START = 3000;
-        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 
-                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-    }
 
     property_get("dalvik.vm.checkjni", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
@@ -557,6 +549,11 @@
 
     property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
 
+    property_get("dalvik.vm.check-dex-sum", propBuf, "");
+    if (strcmp(propBuf, "true") == 0) {
+        checkDexSum = true;
+    }
+
     property_get("log.redirect-stdio", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
         logStdio = true;
@@ -568,19 +565,6 @@
     strcpy(jniOptsBuf, "-Xjniopts:");
     property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
 
-    const char* rootDir = getenv("ANDROID_ROOT");
-    if (rootDir == NULL) {
-        rootDir = "/system";
-        if (!hasDir("/system")) {
-            LOG_FATAL("No root directory specified, and /android does not exist.");
-            return;
-        }
-        setenv("ANDROID_ROOT", rootDir, 1);
-    }
-
-    const char* kernelHack = getenv("LD_ASSUME_KERNEL");
-    //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
-
     /* route exit() to our handler */
     opt.extraInfo = (void*) runtime_exit;
     opt.optionString = "exit";
@@ -654,6 +638,10 @@
         if (opc != NULL) {
             opt.optionString = "-Xgenregmap";
             mOptions.add(opt);
+
+            /* turn on precise GC while we're at it */
+            opt.optionString = "-Xgc:precise";
+            mOptions.add(opt);
         }
     }
 
@@ -700,6 +688,13 @@
         opt.optionString = "-Xint:fast";
         mOptions.add(opt);
     }
+
+    if (checkDexSum) {
+        /* perform additional DEX checksum tests */
+        opt.optionString = "-Xcheckdexsum";
+        mOptions.add(opt);
+    }
+
     if (logStdio) {
         /* convert stdout/stderr to log messages */
         opt.optionString = "-Xlog-stdio";
@@ -767,11 +762,61 @@
      * If this call succeeds, the VM is ready, and we can start issuing
      * JNI calls.
      */
-    if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) {
+    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
         LOGE("JNI_CreateJavaVM failed\n");
         goto bail;
     }
 
+    result = 0;
+
+bail:
+    free(stackTraceFile);
+    return result;
+}
+
+/*
+ * Start the Android runtime.  This involves starting the virtual machine
+ * and calling the "static void main(String[] args)" method in the class
+ * named by "className".
+ */
+void AndroidRuntime::start(const char* className, const bool startSystemServer)
+{
+    LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
+
+    char* slashClassName = NULL;
+    char* cp;
+    JNIEnv* env;
+
+    blockSigpipe();
+
+    /* 
+     * 'startSystemServer == true' means runtime is obslete and not run from 
+     * init.rc anymore, so we print out the boot start event here.
+     */
+    if (startSystemServer) {
+        /* track our progress through the boot sequence */
+        const int LOG_BOOT_PROGRESS_START = 3000;
+        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 
+                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+    }
+
+    const char* rootDir = getenv("ANDROID_ROOT");
+    if (rootDir == NULL) {
+        rootDir = "/system";
+        if (!hasDir("/system")) {
+            LOG_FATAL("No root directory specified, and /android does not exist.");
+            goto bail;
+        }
+        setenv("ANDROID_ROOT", rootDir, 1);
+    }
+
+    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
+    //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
+
+    /* start the virtual machine */
+    if (startVm(&mJavaVM, &env) != 0)
+        goto bail;
+
     /*
      * Register android functions.
      */
@@ -841,7 +886,6 @@
 
 bail:
     free(slashClassName);
-    free(stackTraceFile);
 }
 
 void AndroidRuntime::start()
@@ -1091,7 +1135,6 @@
     REG_JNI(register_android_database_SQLiteQuery),
     REG_JNI(register_android_database_SQLiteStatement),
     REG_JNI(register_android_os_Debug),
-    REG_JNI(register_android_os_Exec),
     REG_JNI(register_android_os_FileObserver),
     REG_JNI(register_android_os_FileUtils),
     REG_JNI(register_android_os_ParcelFileDescriptor),
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index effb1c8..11c608c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -75,9 +75,8 @@
         return result;
     }
  
-    static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, SkPath::BoundsType btype) {
-        SkRect bounds_;
-        obj->computeBounds(&bounds_, btype);
+    static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, int boundstype) {
+        const SkRect& bounds_ = obj->getBounds();
         GraphicsJNI::rect_to_jrectf(bounds_, env, bounds);
     }
  
diff --git a/core/jni/android_os_Exec.cpp b/core/jni/android_os_Exec.cpp
deleted file mode 100644
index ca5e695..0000000
--- a/core/jni/android_os_Exec.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "Exec"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <termios.h>
-
-namespace android
-{
-
-static jclass class_fileDescriptor;
-static jfieldID field_fileDescriptor_descriptor;
-static jmethodID method_fileDescriptor_init;
- 
-
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1,
-    int* pProcessId)
-{
-    char *devname;
-    int ptm;
-    pid_t pid;
-
-    ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
-    if(ptm < 0){
-        LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
-        return -1;
-    }
-    fcntl(ptm, F_SETFD, FD_CLOEXEC);
-
-    if(grantpt(ptm) || unlockpt(ptm) ||
-       ((devname = (char*) ptsname(ptm)) == 0)){
-        LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
-        return -1;
-    }
-    
-    pid = fork();
-    if(pid < 0) {
-        LOGE("- fork failed: %s -\n", strerror(errno));
-        return -1;
-    }
-
-    if(pid == 0){
-        int pts;
-
-        setsid();
-        
-        pts = open(devname, O_RDWR);
-        if(pts < 0) exit(-1);
-
-        dup2(pts, 0);
-        dup2(pts, 1);
-        dup2(pts, 2);
-
-        close(ptm);
-
-        execl(cmd, cmd, arg0, arg1, NULL);
-        exit(-1);
-    } else {
-        *pProcessId = (int) pid;
-        return ptm;
-    }
-}
-
-
-static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
-    jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray)
-{
-    const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
-    String8 cmd_8;
-    if (str) {
-        cmd_8 = String8(str, env->GetStringLength(cmd));
-        env->ReleaseStringCritical(cmd, str);
-    }
-
-    str = arg0 ? env->GetStringCritical(arg0, 0) : 0;
-    const char* arg0Str = 0;
-    String8 arg0_8;
-    if (str) {
-        arg0_8 = String8(str, env->GetStringLength(arg0));
-        env->ReleaseStringCritical(arg0, str);
-        arg0Str = arg0_8.string();
-    }
-
-    str = arg1 ? env->GetStringCritical(arg1, 0) : 0;
-    const char* arg1Str = 0;
-    String8 arg1_8;
-    if (str) {
-        arg1_8 = String8(str, env->GetStringLength(arg1));
-        env->ReleaseStringCritical(arg1, str);
-        arg1Str = arg1_8.string();
-    }
-
-    int procId;
-    int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId);
-    
-    if (processIdArray) {
-        int procIdLen = env->GetArrayLength(processIdArray);
-        if (procIdLen > 0) {
-            jboolean isCopy;
-    
-            int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
-            if (pProcId) {
-                *pProcId = procId;
-                env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
-            }
-        }
-    }
-    
-    jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
-    
-    if (!result) {
-        LOGE("Couldn't create a FileDescriptor.");
-    }
-    else {
-        env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
-    }
-    
-    return result;
-}
-
-
-static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
-    jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
-{
-    int fd;
-    struct winsize sz;
-
-    fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
-    if (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-    
-    sz.ws_row = row;
-    sz.ws_col = col;
-    sz.ws_xpixel = xpixel;
-    sz.ws_ypixel = ypixel;
-    
-    ioctl(fd, TIOCSWINSZ, &sz);
-}
-
-static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
-    jint procId) {
-    int status;
-    waitpid(procId, &status, 0);
-    int result = 0;
-    if (WIFEXITED(status)) {
-        result = WEXITSTATUS(status);
-    }
-    return result;
-}
-
-static JNINativeMethod method_table[] = {
-    { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
-        (void*) android_os_Exec_createSubProcess },
-    { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V",
-        (void*) android_os_Exec_setPtyWindowSize},
-    { "waitFor", "(I)I",
-        (void*) android_os_Exec_waitFor}
-};
-
-int register_android_os_Exec(JNIEnv *env)
-{
-    class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
-
-    if (class_fileDescriptor == NULL) {
-        LOGE("Can't find java/io/FileDescriptor");
-        return -1;
-    }
-
-    field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
-
-    if (field_fileDescriptor_descriptor == NULL) {
-        LOGE("Can't find FileDescriptor.descriptor");
-        return -1;
-    }
-
-    method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V");
-    if (method_fileDescriptor_init == NULL) {
-        LOGE("Can't find FileDescriptor.init");
-        return -1;
-     }
-
-    return AndroidRuntime::registerNativeMethods(
-        env, "android/os/Exec",
-        method_table, NELEM(method_table));
-}
-
-};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index caa1318..df599da 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -25,7 +25,7 @@
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
     <eat-comment />
-    
+
     <!-- Used for permissions that can be used to make the user spend money
          without their direct involvement.  For example, this is the group
          for permissions that allow you to directly place phone calls,
@@ -54,7 +54,7 @@
     <!-- Permissions for accessing messages -->
     <!-- ================================== -->
     <eat-comment />
-    
+
     <!-- Used for permissions that allow an application to send messages
          on behalf of the user or intercept messages being received by the
          user.  This is primarily intended for SMS/MMS messaging, such as
@@ -104,7 +104,7 @@
     <!-- Permissions for accessing personal info (contacts and calendar) -->
     <!-- =============================================================== -->
     <eat-comment />
-    
+
     <!-- Used for permissions that provide access to the user's private data,
          such as contacts, calendar events, e-mail messages, etc.  This includes
          both reading and writing of this data (which should generally be
@@ -158,8 +158,8 @@
         android:description="@string/permdesc_writeCalendar" />
 
     <!-- Allows an application to read the user dictionary. This should
-         really only be required by an IME, or a dictionary editor like 
-         the Settings app. 
+         really only be required by an IME, or a dictionary editor like
+         the Settings app.
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_USER_DICTIONARY"
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
@@ -179,7 +179,7 @@
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
     <eat-comment />
-    
+
     <!-- Used for permissions that allow access to the user's current
          location. -->
     <permission-group android:name="android.permission-group.LOCATION"
@@ -218,7 +218,7 @@
     <!-- Permissions for accessing networks -->
     <!-- ======================================= -->
     <eat-comment />
-    
+
     <!-- Used for permissions that provide access to networking services.  The
          main permission here is internet access, but this is also an
          appropriate group for accessing or modifying any network configuration
@@ -259,7 +259,7 @@
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
     <eat-comment />
-    
+
     <!-- Permissions for direct access to Google accounts.
          Note that while right now this is only used for Google accounts,
          we expect in the future to have a more general account management
@@ -280,7 +280,7 @@
     <!-- Permissions for accessing hardware -->
     <!-- ================================== -->
     <eat-comment />
-    
+
     <!-- Used for permissions that provide direct access to the hardware on
          the device.  This includes audio, the camera, vibrator, etc. -->
     <permission-group android:name="android.permission-group.HARDWARE_CONTROLS"
@@ -333,7 +333,7 @@
     <!-- Permissions associated with telephony state -->
     <!-- =========================================== -->
     <eat-comment />
-    
+
     <!-- Used for permissions that are associated with accessing and modifyign
          telephony state: intercepting outgoing calls, reading
          and modifying the phone state.  Note that
@@ -387,7 +387,7 @@
     <!-- Permissions for low-level system interaction -->
     <!-- ============================================ -->
     <eat-comment />
-    
+
     <!-- Group of permissions that are related to system APIs.  Many
          of these are not permissions the user will be expected to understand,
          and such permissions should generally be marked as "normal" protection
@@ -611,7 +611,7 @@
                 android:description="@string/permdesc_writeApnSettings"
                 android:label="@string/permlab_writeApnSettings" />
 
-    <!-- Allows an application to allow access the subscribed feeds 
+    <!-- Allows an application to allow access the subscribed feeds
          ContentProvider. -->
     <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -623,7 +623,7 @@
         android:label="@string/permlab_subscribedFeedsWrite"
         android:description="@string/permdesc_subscribedFeedsWrite"
         android:protectionLevel="dangerous" />
-        
+
     <!-- Allows applications to change network connectivity state -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -667,7 +667,7 @@
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
     <eat-comment />
-    
+
     <!-- Group of permissions that are related to development features.  These
          are not permissions that should appear in normal applications; they
          protect APIs that are intended only to be used for development
@@ -1000,6 +1000,11 @@
                 android:excludeFromRecents="true">
         </activity>
 
+        <activity android:name="android.accounts.ChooseAccountActivity"
+                android:excludeFromRecents="true"
+                android:exported="true">
+        </activity>
+
         <provider android:name=".content.SyncProvider"
                 android:authorities="sync" android:multiprocess="false" />
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 972953b..da51338 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -64,7 +64,7 @@
 
         <!-- Inverse hint text color -->
         <attr name="textColorHintInverse" format="reference|color" />
-        
+
         <!-- Bright text color. Only differentiates based on the disabled state. -->
         <attr name="textColorPrimaryDisableOnly" format="reference|color" />
 
@@ -101,20 +101,20 @@
 
         <!-- Text color, typeface, size, and style for the text inside of a button. -->
         <attr name="textAppearanceButton" format="reference" />
-        
+
         <!-- A styled string, specifying the style to be used for showing
              inline candidate text when composing with an input method.  The
              text itself will be ignored, but the style spans will be applied
              to the candidate text as it is edited. -->
         <attr name="candidatesTextStyleSpans" format="reference|string" />
-        
+
         <!-- Drawable to use for check marks -->
         <attr name="textCheckMark" format="reference" />
         <attr name="textCheckMarkInverse" format="reference" />
 
         <!-- Drawable to use for multiple choice indicators-->
         <attr name="listChoiceIndicatorMultiple" format="reference" />
-        
+
         <!-- Drawable to use for single choice indicators-->
         <attr name="listChoiceIndicatorSingle" format="reference" />
 
@@ -139,7 +139,7 @@
         <!-- Gallery styles -->
         <!-- ============== -->
         <eat-comment />
-        
+
         <!-- The preferred background for gallery items. This should be set
              as the background of any Views you provide from the Adapter. -->
         <attr name="galleryItemBackground" format="reference" />
@@ -159,20 +159,20 @@
         <attr name="listSeparatorTextViewStyle" format="reference" />
         <!-- The preferred left padding for an expandable list item (for child-specific layouts,
              use expandableListPreferredChildPaddingLeft). This takes into account
-             the indicator that will be shown to next to the item. --> 
+             the indicator that will be shown to next to the item. -->
         <attr name="expandableListPreferredItemPaddingLeft" format="dimension" />
         <!-- The preferred left padding for an expandable list item that is a child.
-             If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. --> 
+             If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. -->
         <attr name="expandableListPreferredChildPaddingLeft" format="dimension" />
         <!-- The preferred left bound for an expandable list item's indicator. For a child-specific
-             indicator, use expandableListPreferredChildIndicatorLeft. --> 
+             indicator, use expandableListPreferredChildIndicatorLeft. -->
         <attr name="expandableListPreferredItemIndicatorLeft" format="dimension" />
         <!-- The preferred right bound for an expandable list item's indicator. For a child-specific
-             indicator, use expandableListPreferredChildIndicatorRight. --> 
+             indicator, use expandableListPreferredChildIndicatorRight. -->
         <attr name="expandableListPreferredItemIndicatorRight" format="dimension" />
-        <!-- The preferred left bound for an expandable list child's indicator. --> 
+        <!-- The preferred left bound for an expandable list child's indicator. -->
         <attr name="expandableListPreferredChildIndicatorLeft" format="dimension" />
-        <!-- The preferred right bound for an expandable list child's indicator. --> 
+        <!-- The preferred right bound for an expandable list child's indicator. -->
         <attr name="expandableListPreferredChildIndicatorRight" format="dimension" />
 
         <!-- ============= -->
@@ -221,7 +221,7 @@
              any of the attributes defined by
              {@link android.R.styleable#WindowAnimation}. -->
         <attr name="windowAnimationStyle" format="reference" />
-    
+
         <!-- Defines the default soft input state that this window would
              like when it is displayed. -->
         <attr name="windowSoftInputMode">
@@ -243,7 +243,7 @@
             <!-- Always make the soft input area visible when this window
                  has input focus. -->
             <flag name="stateAlwaysVisible" value="5" />
-            
+
             <!-- The window resize/pan adjustment has not been specified,
                  the system will automatically select between resize and pan
                  modes, depending
@@ -270,7 +270,7 @@
              use the window's theme to show a preview of it before your
              actual instance is shown to the user. -->
         <attr name="windowDisablePreview" format="boolean" />
-        
+
         <!-- Flag indicating that this window should not be displayed at all.
              The default value is false; if set to true, and this window is
              the main window of an Activity, then it will never actually
@@ -278,13 +278,13 @@
              must immediately quit without waiting for user interaction,
              because there will be no such interaction coming. -->
         <attr name="windowNoDisplay" format="boolean" />
-        
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
         <eat-comment />
         <attr name="alertDialogStyle" format="reference" />
-        
+
         <!-- ============ -->
         <!-- Panel styles -->
         <!-- ============ -->
@@ -381,7 +381,7 @@
         <!-- Preference styles   -->
         <!-- =================== -->
         <eat-comment />
-        
+
         <!-- Default style for PreferenceScreen. -->
         <attr name="preferenceScreenStyle" format="reference" />
         <!-- Default style for PreferenceCategory. -->
@@ -402,7 +402,7 @@
         <attr name="ringtonePreferenceStyle" format="reference" />
         <!-- The preference layout that has the child/tabbed effect. -->
         <attr name="preferenceLayoutChild" format="reference" />
-        
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -420,7 +420,7 @@
     </ul>
         -->
     <attr name="textSize" format="dimension" />
-    
+
     <!-- Default text typeface. -->
     <attr name="typeface">
         <enum name="normal" value="0" />
@@ -428,26 +428,26 @@
         <enum name="serif" value="2" />
         <enum name="monospace" value="3" />
     </attr>
-    
+
     <!-- Default text typeface style. -->
     <attr name="textStyle">
         <flag name="normal" value="0" />
         <flag name="bold" value="1" />
         <flag name="italic" value="2" />
     </attr>
-    
+
     <!-- Color of text (usually same as colorForeground). -->
     <attr name="textColor" format="reference|color" />
-    
+
     <!-- Color of highlighted text. -->
     <attr name="textColorHighlight" format="reference|color" />
-    
+
     <!-- Color of hint text (displayed when the field is empty). -->
     <attr name="textColorHint" format="reference|color" />
-    
+
     <!-- Color of link text (URLs). -->
     <attr name="textColorLink" format="reference|color" />
-    
+
     <!-- Where to ellipsize text. -->
     <attr name="ellipsize">
         <enum name="none" value="0" />
@@ -456,7 +456,7 @@
         <enum name="end" value="3" />
         <enum name="marquee" value="4" />
     </attr>
-    
+
     <!-- The type of data being placed in a text field, used to help an
          input method decide how to let the user enter text.  The constants
          here correspond to those defined by
@@ -663,7 +663,7 @@
     <attr name="x" format="dimension" />
     <!-- A coordinate in the Y dimension. -->
     <attr name="y" format="dimension" />
-          
+
     <!-- Specifies how to place an object, both
          its x and y axis, within a larger containing object. -->
     <attr name="gravity">
@@ -769,11 +769,11 @@
     <!-- ========================== -->
     <eat-comment />
 
-    <!-- This enum provides the same keycode values as can be found in 
+    <!-- This enum provides the same keycode values as can be found in
         {@link android.view.KeyEvent} -->
     <attr name="keycode">
         <enum name="KEYCODE_UNKNOWN" value="0" />
-        <enum name="KEYCODE_SOFT_LEFT" value="1" />    
+        <enum name="KEYCODE_SOFT_LEFT" value="1" />
         <enum name="KEYCODE_SOFT_RIGHT" value="2" />
         <enum name="KEYCODE_HOME" value="3" />
         <enum name="KEYCODE_BACK" value="4" />
@@ -906,7 +906,7 @@
         <attr name="bottomMedium" format="reference|color" />
         <attr name="centerMedium" format="reference|color" />
     </declare-styleable>
-    
+
     <!-- Window animation class attributes. -->
     <declare-styleable name="WindowAnimation">
         <!-- The animation used when a window is being added. -->
@@ -950,7 +950,7 @@
              allows you to later retrieve the view
              with <code>findViewById(R.id.my_id)</code>. -->
         <attr name="id" format="reference" />
-        
+
         <!-- Supply a tag for this view containing a String, to be retrieved
              later with {@link android.view.View#getTag View.getTag()} or
              searched for with {@link android.view.View#findViewWithTag
@@ -958,7 +958,7 @@
              IDs (through the android:id attribute) instead of tags because
              they are faster and allow for compile-time type checking. -->
         <attr name="tag" format="string" />
-        
+
         <!-- The initial horizontal scroll offset, in pixels.-->
         <attr name="scrollX" format="dimension" />
 
@@ -972,7 +972,7 @@
         <attr name="background" format="reference|color" />
 
         <!-- Sets the padding, in pixels, of all four edges.  Padding is defined as
-             space between the edges of the view and the view's content. A views size 
+             space between the edges of the view and the view's content. A views size
              will include it's padding.  If a {@link android.R.attr#background}
              is provided, the padding will initially be set to that (0 if the
              drawable does not have padding).  Explicitly setting a padding value
@@ -1027,12 +1027,12 @@
         </attr>
 
         <!-- Controls the scrollbar style and position. The scrollbars can be overlaid or
-             inset. When inset, they add to the padding of the view. And the 
-             scrollbars can be drawn inside the padding area or on the edge of 
-             the view. For example, if a view has a background drawable and you 
-             want to draw the scrollbars inside the padding specified by the 
-             drawable, you can use insideOverlay or insideInset. If you want them 
-             to appear at the edge of the view, ignoring the padding, then you can 
+             inset. When inset, they add to the padding of the view. And the
+             scrollbars can be drawn inside the padding area or on the edge of
+             the view. For example, if a view has a background drawable and you
+             want to draw the scrollbars inside the padding specified by the
+             drawable, you can use insideOverlay or insideInset. If you want them
+             to appear at the edge of the view, ignoring the padding, then you can
              use outsideOverlay or outsideInset.-->
         <attr name="scrollbarStyle">
             <!-- Inside the padding and overlaid -->
@@ -1044,14 +1044,14 @@
             <!-- Edge of the view and inset -->
             <enum name="outsideInset" value="0x03000000" />
         </attr>
-        
+
         <!-- Set this if the view will serve as a scrolling container, meaing
              that it can be resized to shrink its overall window so that there
              will be space for an input method.  If not set, the default
              value will be true if "scrollbars" has the vertical scrollbar
              set, else it will be false. -->
         <attr name="isScrollContainer" format="boolean" />
-        
+
         <!-- Sets the width of vertical scrollbars and height of horizontal scrollbars. -->
         <attr name="scrollbarSize" format="dimension" />
         <!-- Defines the horizontal scrollbar thumb drawable. -->
@@ -1113,10 +1113,10 @@
 
         <!-- Defines whether this view reacts to click events. -->
         <attr name="clickable" format="boolean" />
-        
+
         <!-- Defines whether this view reacts to long click events. -->
         <attr name="longClickable" format="boolean" />
-        
+
         <!-- If unset, no state will be saved for this view when it is being
              frozen. The default is true, allowing the view to be saved
              (however it also must have an ID assigned to it for its
@@ -1124,7 +1124,7 @@
              state for this view, not for its children which may still
              be saved. -->
         <attr name="saveEnabled" format="boolean" />
-        
+
         <!-- Defines the quality of translucent drawing caches. This property is used
              only when the drawing cache is enabled and translucent. The default value is auto. -->
         <attr name="drawingCacheQuality">
@@ -1142,16 +1142,16 @@
         <!-- Controls whether the view's window should keep the screen on
              while visible. -->
         <attr name="keepScreenOn" format="boolean" />
-        
+
         <!-- When this attribute is set to true, the view gets its drawable state
              (focused, pressed, etc.) from its direct parent rather than from itself. -->
         <attr name="duplicateParentState" format="boolean" />
-        
+
         <!-- Defines the minimum height of the view. It is not guaranteed
              the view will be able to achieve this minimum height (for example,
              if its parent layout constrains it with less available height). -->
         <attr name="minHeight" />
-        
+
         <!-- Defines the minimum width of the view. It is not guaranteed
              the view will be able to achieve this minimum width (for example,
              if its parent layout constrains it with less available width). -->
@@ -1201,7 +1201,7 @@
             <flag name="animation" value="0x1" />
             <!-- The drawing cache is persisted after a scroll. -->
             <flag name="scrolling" value="0x2" />
-            <!-- The drawing cache is always persisted. -->            
+            <!-- The drawing cache is always persisted. -->
             <flag name="all" value="0x3" />
         </attr>
         <!-- Defines whether the ViewGroup should always draw its children using their
@@ -1314,7 +1314,7 @@
              method should be considered an option as the default. -->
         <attr name="isDefault" format="boolean" />
     </declare-styleable>
-    
+
     <!-- =============================== -->
     <!-- Widget package class attributes -->
     <!-- =============================== -->
@@ -1323,7 +1323,7 @@
     <declare-styleable name="AbsListView">
          <!-- Drawable used to indicate the currently selected item in the list. -->
         <attr name="listSelector" format="color|reference" />
-        <!-- When set to true, the selector will be drawn over the selected item. 
+        <!-- When set to true, the selector will be drawn over the selected item.
              Otherwise the selector is drawn behind the selected item. The default
              value is false. -->
         <attr name="drawSelectorOnTop" format="boolean" />
@@ -1346,13 +1346,13 @@
                  already visible on screen. -->
             <enum name="normal" value="1" />
             <!-- The list will automatically scroll to the bottom, no matter what items
-                 are currently visible. --> 
+                 are currently visible. -->
             <enum name="alwaysScroll" value="2" />
         </attr>
         <!-- Indicates that this list will always be drawn on top of solid, single-color
              opaque background. This allows the list to optimize drawing. -->
         <attr name="cacheColorHint" format="color" />
-        <!-- Enables the fast scroll thumb that can be dragged to quickly scroll through 
+        <!-- Enables the fast scroll thumb that can be dragged to quickly scroll through
              the list. -->
         <attr name="fastScrollEnabled" format="boolean" />
         <!-- When set to true, the list will use a more refined calculation
@@ -1441,7 +1441,7 @@
         <!-- Defines whether the foreground drawable should be drawn inside the padding.
              This property is turned on by default. -->
         <attr name="foregroundInsidePadding" format="boolean" />
-        <!-- Determines whether to measure all children or just those in 
+        <!-- Determines whether to measure all children or just those in
              the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
         <attr name="measureAllChildren" format="boolean" />
     </declare-styleable>
@@ -1451,14 +1451,14 @@
         <!-- Indicator shown beside the child View. This can be a stateful Drawable. -->
         <attr name="childIndicator" format="reference" />
         <!-- The left bound for an item's indicator. To specify a left bound specific to children,
-             use childIndicatorLeft. --> 
+             use childIndicatorLeft. -->
         <attr name="indicatorLeft" format="dimension" />
         <!-- The right bound for an item's indicator. To specify a right bound specific to children,
-             use childIndicatorRight. --> 
+             use childIndicatorRight. -->
         <attr name="indicatorRight" format="dimension" />
-        <!-- The left bound for a child's indicator. --> 
+        <!-- The left bound for a child's indicator. -->
         <attr name="childIndicatorLeft" format="dimension" />
-        <!-- The right bound for a child's indicator. --> 
+        <!-- The right bound for a child's indicator. -->
         <attr name="childIndicatorRight" format="dimension" />
         <!-- Drawable or color that is used as a divider for children. (It will drawn
              below and above child items.) The height of this will be the same as
@@ -1509,10 +1509,10 @@
         <!-- Set this to true if you want the ImageView to adjust its bounds
              to preserve the aspect ratio of its drawable. -->
         <attr name="adjustViewBounds" format="boolean" />
-        <!-- An optional argument to supply a maximum width for this view. 
+        <!-- An optional argument to supply a maximum width for this view.
              See {see android.widget.ImageView#setMaxWidth} for details. -->
         <attr name="maxWidth" format="dimension" />
-        <!-- An optional argument to supply a maximum height for this view. 
+        <!-- An optional argument to supply a maximum height for this view.
              See {see android.widget.ImageView#setMaxHeight} for details. -->
         <attr name="maxHeight" format="dimension" />
         <!-- Set a tinting color for the image -->
@@ -1566,9 +1566,9 @@
         <!-- Height of the divider. Will use the intrinsic height of the divider if this
              is not specified. -->
         <attr name="dividerHeight" format="dimension" />
-        <!-- Defines the choice behavior for the List. By default, Lists do not have 
+        <!-- Defines the choice behavior for the List. By default, Lists do not have
              any choice behavior. By setting the choiceMode to singleChoice, the List
-             allows up to one item to be in a chosen state. By setting the choiceMode to 
+             allows up to one item to be in a chosen state. By setting the choiceMode to
              multipleChoice, the list allows any number of items to be chosen. -->
         <attr name="choiceMode">
             <!-- Normal list that does not indicate choices -->
@@ -1613,7 +1613,7 @@
         <!-- 'More' icon -->
         <attr name="moreIcon" format="reference" />
     </declare-styleable>
-    
+
     <declare-styleable name="ProgressBar">
         <!-- Defines the maximum value the progress can take. -->
         <attr name="max" format="integer" />
@@ -1646,27 +1646,27 @@
         <attr name="maxWidth" />
         <attr name="minHeight" format="dimension" />
         <attr name="maxHeight" />
-        <attr name="interpolator" format="reference" />        
+        <attr name="interpolator" format="reference" />
     </declare-styleable>
-    
+
     <declare-styleable name="SeekBar">
-        <!-- Draws the thumb on a seekbar -->    
+        <!-- Draws the thumb on a seekbar -->
         <attr name="thumb" format="reference" />
         <!-- An offset for the thumb that allows it to extend out of the range of the track. -->
-        <attr name="thumbOffset" format="dimension" /> 
+        <attr name="thumbOffset" format="dimension" />
     </declare-styleable>
-    
+
     <declare-styleable name="RatingBar">
-        <!-- The number of stars (or rating items) to show. -->    
-        <attr name="numStars" format="integer" /> 
-        <!-- The rating to set by default. -->    
-        <attr name="rating" format="float" /> 
-        <!-- The step size of the rating. -->    
-        <attr name="stepSize" format="float" /> 
-        <!-- Whether this rating bar is an indicator (and non-changeable by the user). -->    
-        <attr name="isIndicator" format="boolean" /> 
+        <!-- The number of stars (or rating items) to show. -->
+        <attr name="numStars" format="integer" />
+        <!-- The rating to set by default. -->
+        <attr name="rating" format="float" />
+        <!-- The step size of the rating. -->
+        <attr name="stepSize" format="float" />
+        <!-- Whether this rating bar is an indicator (and non-changeable by the user). -->
+        <attr name="isIndicator" format="boolean" />
     </declare-styleable>
-    
+
     <declare-styleable name="RadioGroup">
         <!-- The id of the child radio button that should be checked by default
              within this radio group. -->
@@ -1688,7 +1688,7 @@
              indices are ignored. You can shrink all columns by using the
              value "*" instead. Note that a column can be marked stretchable
              and shrinkable at the same time. -->
-        <attr name="shrinkColumns" format="string" /> 
+        <attr name="shrinkColumns" format="string" />
         <!-- The 0 based index of the columns to collapse. The column indices
              must be separated by a comma: 1, 2, 5. Illegal and duplicate
              indices are ignored. -->
@@ -1789,7 +1789,7 @@
         <attr name="minEms" format="integer" min="0" />
         <!-- Makes the TextView be at least this many pixels wide -->
         <attr name="minWidth" />
-        <!-- Specifies how to align the text by the view's x and/or y axis 
+        <!-- Specifies how to align the text by the view's x and/or y axis
              when the text is smaller than the view. -->
         <attr name="gravity" />
         <!-- Whether the text is allowed to be wider than the view (and
@@ -1807,10 +1807,10 @@
              attribute.  (If both singleLine and inputType are supplied,
              the inputType flags will override the value of singleLine.)
              {@deprecated This attribute is deprecated and is replaced by the textMultiLine flag
-             in the inputType attribute.  Use caution when altering existing layouts, as the 
-             default value of singeLine is false (multi-line mode), but if you specify any 
-             value for inputType, the default is single-line mode.  (If both singleLine and 
-             inputType attributes are found,  the inputType flags will override the value of 
+             in the inputType attribute.  Use caution when altering existing layouts, as the
+             default value of singeLine is false (multi-line mode), but if you specify any
+             value for inputType, the default is single-line mode.  (If both singleLine and
+             inputType attributes are found,  the inputType flags will override the value of
              singleLine.) } -->
         <attr name="singleLine" format="boolean" />
         <!-- {@deprecated Use state_enabled instead.} -->
@@ -1914,7 +1914,7 @@
         <attr name="lineSpacingExtra" format="dimension" />
         <!-- Extra spacing between lines of text, as a multiplier. -->
         <attr name="lineSpacingMultiplier" format="float" />
-        <!-- The number of times to repeat the marquee animation. Only applied if the 
+        <!-- The number of times to repeat the marquee animation. Only applied if the
              TextView has marquee enabled. -->
         <attr name="marqueeRepeatLimit" format="integer">
             <!-- Indicates that marquee should repeat indefinitely  -->
@@ -2005,7 +2005,7 @@
         <!-- The prompt to display when the spinner's dialog is shown. -->
         <attr name="prompt" format="reference" />
     </declare-styleable>
-    <declare-styleable name="DatePicker">  
+    <declare-styleable name="DatePicker">
         <!-- The first year (inclusive) i.e. 1940 -->
         <attr name="startYear" format="integer" />
         <!-- The last year (inclusive) i.e. 2010 -->
@@ -2129,7 +2129,7 @@
              {@link android.graphics.drawable.Drawable#setVisible} -->
         <attr name="visible" format="boolean" />
     </declare-styleable>
-    
+
     <declare-styleable name="StateListDrawable">
         <attr name="visible" />
         <!-- If true, allows the drawable's padding to change based on the
@@ -2145,7 +2145,7 @@
              current state. -->
         <attr name="constantSize" format="boolean" />
     </declare-styleable>
-    
+
     <declare-styleable name="AnimationDrawable">
         <attr name="visible" />
         <attr name="variablePadding" />
@@ -2154,15 +2154,15 @@
              restarting at the first frame after the last has finished. -->
         <attr name="oneshot" format="boolean" />
     </declare-styleable>
-    
+
     <declare-styleable name="AnimationDrawableItem">
         <!-- Amount of time (in milliseconds) to display this frame. -->
-        <attr name="duration" format="integer" /> 
+        <attr name="duration" format="integer" />
         <!-- Reference to a drawable resource to use for the frame.  If not
              given, the drawable must be defined by the first child tag. -->
         <attr name="drawable" format="reference" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawable">
         <attr name="visible" />
         <attr name="shape">
@@ -2185,18 +2185,18 @@
         <attr name="thickness" format="dimension" />
         <attr name="useLevel" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawableSize">
         <attr name="width" />
         <attr name="height" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawableGradient">
         <attr name="startColor" format="color" />
         <!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. -->
         <attr name="centerColor" format="color" />
         <attr name="endColor" format="color" />
-        <attr name="useLevel" format="boolean" />        
+        <attr name="useLevel" format="boolean" />
         <attr name="angle" format="float" />
         <attr name="type">
             <enum name="linear" value="0" />
@@ -2207,18 +2207,18 @@
         <attr name="centerY" format="float|fraction" />
         <attr name="gradientRadius" format="float|fraction" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawableSolid">
         <attr name="color" format="color" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawableStroke">
         <attr name="width" />
         <attr name="color" />
         <attr name="dashWidth" format="dimension" />
         <attr name="dashGap" format="dimension" />
     </declare-styleable>
-    
+
     <declare-styleable name="DrawableCorners">
         <attr name="radius" format="dimension" />
         <attr name="topLeftRadius" format="dimension" />
@@ -2226,14 +2226,14 @@
         <attr name="bottomLeftRadius" format="dimension" />
         <attr name="bottomRightRadius" format="dimension" />
     </declare-styleable>
-    
+
     <declare-styleable name="GradientDrawablePadding">
         <attr name="left" format="dimension" />
         <attr name="top" format="dimension" />
         <attr name="right" format="dimension" />
         <attr name="bottom" format="dimension" />
     </declare-styleable>
-    
+
     <declare-styleable name="LayerDrawableItem">
         <attr name="left" />
         <attr name="top" />
@@ -2242,7 +2242,7 @@
         <attr name="drawable" />
         <attr name="id" />
     </declare-styleable>
-    
+
     <declare-styleable name="LevelListDrawableItem">
         <!-- The minimum level allowed for this item. -->
         <attr name="minLevel" format="integer" />
@@ -2250,7 +2250,7 @@
         <attr name="maxLevel" format="integer" />
         <attr name="drawable" />
     </declare-styleable>
-    
+
     <declare-styleable name="RotateDrawable">
         <attr name="visible" />
         <attr name="fromDegrees" format="float" />
@@ -2406,7 +2406,7 @@
     <declare-styleable name="AnimationSet">
         <attr name="shareInterpolator" format="boolean" />
     </declare-styleable>
-    
+
     <declare-styleable name="Animation">
         <!-- Defines the interpolator used to smooth the animation movement in time. -->
         <attr name="interpolator" />
@@ -2449,14 +2449,14 @@
             <enum name="bottom" value="-1" />
         </attr>
     </declare-styleable>
-    
+
     <declare-styleable name="RotateAnimation">
         <attr name="fromDegrees" />
         <attr name="toDegrees" />
         <attr name="pivotX" />
         <attr name="pivotY" />
     </declare-styleable>
-    
+
     <declare-styleable name="ScaleAnimation">
         <attr name="fromXScale" format="float" />
         <attr name="toXScale" format="float" />
@@ -2465,14 +2465,14 @@
         <attr name="pivotX" />
         <attr name="pivotY" />
     </declare-styleable>
-    
+
     <declare-styleable name="TranslateAnimation">
         <attr name="fromXDelta" format="float|fraction" />
         <attr name="toXDelta" format="float|fraction" />
         <attr name="fromYDelta" format="float|fraction" />
         <attr name="toYDelta" format="float|fraction" />
     </declare-styleable>
-    
+
     <declare-styleable name="AlphaAnimation">
         <attr name="fromAlpha" format="float" />
         <attr name="toAlpha" format="float" />
@@ -2534,12 +2534,12 @@
         <!-- This is the amount of deceleration to add when easing in. -->
         <attr name="factor" format="float" />
     </declare-styleable>
-    
+
     <declare-styleable name="DecelerateInterpolator">
         <!-- This is the amount of acceleration to add when easing out. -->
         <attr name="factor" />
     </declare-styleable>
-    
+
     <declare-styleable name="CycleInterpolator">
         <attr name="cycles" format="float" />
     </declare-styleable>
@@ -2649,18 +2649,18 @@
     </declare-styleable>
     <!-- State array representing an expandable list child's indicator. -->
     <declare-styleable name="ExpandableListChildIndicatorState">
-        <!-- State identifier indicating the child is the last child within its group. --> 
+        <!-- State identifier indicating the child is the last child within its group. -->
         <attr name="state_last" />
     </declare-styleable>
     <!-- State array representing an expandable list group's indicator. -->
     <declare-styleable name="ExpandableListGroupIndicatorState">
-        <!-- State identifier indicating the group is expanded. --> 
+        <!-- State identifier indicating the group is expanded. -->
         <attr name="state_expanded" format="boolean" />
-        <!-- State identifier indicating the group is empty (has no children). --> 
+        <!-- State identifier indicating the group is empty (has no children). -->
         <attr name="state_empty" format="boolean" />
     </declare-styleable>
     <declare-styleable name="PopupWindowBackgroundState">
-        <!-- State identifier indicating the popup will be above the anchor. --> 
+        <!-- State identifier indicating the popup will be above the anchor. -->
         <attr name="state_above_anchor" format="boolean" />
     </declare-styleable>
 
@@ -2670,7 +2670,7 @@
     <eat-comment />
 
     <!-- Searchable activities and applications must provide search configuration information
-        in an XML file, typically called searchable.xml.  This file is referenced in your manifest. 
+        in an XML file, typically called searchable.xml.  This file is referenced in your manifest.
         For a more in-depth discussion of search configuration, please refer to
         {@link android.app.SearchManager}. -->
     <declare-styleable name="Searchable">
@@ -2679,29 +2679,29 @@
              plain text.  This is a reference to a drawable (icon) resource.
              <i>Optional attribute.</i> -->
         <attr name="icon" />
-        <!-- This is the user-displayed name of the searchable activity.  <i>Required 
+        <!-- This is the user-displayed name of the searchable activity.  <i>Required
             attribute.</i> -->
         <attr name="label" />
-        <!-- If supplied, this string will be displayed as a hint to the user.  <i>Optional 
+        <!-- If supplied, this string will be displayed as a hint to the user.  <i>Optional
             attribute.</i> -->
         <attr name="hint" />
         <!-- If supplied, this string will be displayed as the text of the "Search" button.
-          <i>Optional attribute.</i> 
+          <i>Optional attribute.</i>
           {@deprecated This will create a non-standard UI appearance, because the search bar UI is
                        changing to use only icons for its buttons.}-->
         <attr name="searchButtonText" format="string" />
         <attr name="inputType" />
         <attr name="imeOptions" />
-        
+
         <!-- Additional features are controlled by mode bits in this field.  Omitting
-            this field, or setting to zero, provides default behavior.  <i>Optional attribute.</i> 
+            this field, or setting to zero, provides default behavior.  <i>Optional attribute.</i>
         -->
         <attr name="searchMode">
           <!-- If set, this flag enables the display of the search target (label) within the
                search bar.  If neither bad mode is selected, no badge will be shown. -->
           <flag name="showSearchLabelAsBadge" value="0x04" />
           <!-- If set, this flag enables the display of the search target (icon) within the
-               search bar.  (Note, overrides showSearchLabel)  If neither bad mode is selected, 
+               search bar.  (Note, overrides showSearchLabel)  If neither bad mode is selected,
                no badge will be shown.-->
           <flag name="showSearchIconAsBadge" value="0x08" />
           <!-- If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA to
@@ -2715,11 +2715,11 @@
                values are not suitable for user inspection and editing. -->
           <flag name="queryRewriteFromText" value="0x20" />
         </attr>
-        
+
         <!-- Voice search features are controlled by mode bits in this field.  Omitting
             this field, or setting to zero, provides default behavior.
             If showVoiceSearchButton is set, then launchWebSearch or launchRecognizer must
-            also be set.  <i>Optional attribute.</i> 
+            also be set.  <i>Optional attribute.</i>
         -->
         <attr name="voiceSearchMode">
           <!-- If set, display a voice search button.  This only takes effect if voice search is
@@ -2738,9 +2738,9 @@
         </attr>
 
         <!-- If provided, this specifies the language model that should be used by the
-             voice recognition system.  See 
-             {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information. 
-             If not provided, the default value 
+             voice recognition system.  See
+             {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
+             If not provided, the default value
              {@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM } will be used. -->
         <attr name="voiceLanguageModel" format="string" />
         <!-- If provided, this specifies a prompt that will be displayed during voice input. -->
@@ -2750,14 +2750,14 @@
         <attr name="voiceLanguage" format="string" />
         <!-- If provided, enforces the maximum number of results to return, including the "best"
              result which will always be provided as the SEARCH intent's primary query.  Must be one
-             or greater.  If not provided, the recognizer will choose how many results to return. 
+             or greater.  If not provided, the recognizer will choose how many results to return.
              -->
         <attr name="voiceMaxResults" format="integer" />
 
         <!-- If provided, this is the trigger indicating that the searchable activity
             provides suggestions as well.  The value must be a fully-qualified content provider
-            authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the 
-            "android:authorities" tag in your content provider's manifest entry.  <i>Optional 
+            authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
+            "android:authorities" tag in your content provider's manifest entry.  <i>Optional
             attribute.</i> -->
         <attr name="searchSuggestAuthority" format="string" />
         <!-- If provided, this will be inserted in the suggestions query Uri, after the authority
@@ -2765,22 +2765,22 @@
             -->
         <attr name="searchSuggestPath" format="string" />
         <!-- If provided, suggestion queries will be passed into your query function
-            as the <i>selection</i> parameter.  Typically this will be a WHERE clause for your 
-            database, and will contain a single question mark, which represents the actual query 
+            as the <i>selection</i> parameter.  Typically this will be a WHERE clause for your
+            database, and will contain a single question mark, which represents the actual query
             string that has been typed by the user.  If not provided, then the user query text
-            will be appended to the query Uri (after an additional "/".)  <i>Optional 
+            will be appended to the query Uri (after an additional "/".)  <i>Optional
             attribute.</i> -->
         <attr name="searchSuggestSelection" format="string" />
 
-        <!-- If provided, and not overridden by an action in the selected suggestion, this 
+        <!-- If provided, and not overridden by an action in the selected suggestion, this
             string will be placed in the action field of the {@link android.content.Intent Intent}
             when the user clicks a suggestion.  <i>Optional attribute.</i> -->
         <attr name="searchSuggestIntentAction" format="string" />
-        <!-- If provided, and not overridden by an action in the selected suggestion, this 
-            string will be placed in the data field of the {@link android.content.Intent Intent} 
+        <!-- If provided, and not overridden by an action in the selected suggestion, this
+            string will be placed in the data field of the {@link android.content.Intent Intent}
             when the user clicks a suggestion.  <i>Optional attribute.</i> -->
         <attr name="searchSuggestIntentData" format="string" />
-        
+
     </declare-styleable>
 
     <!-- In order to process special action keys during search, you must define them using
@@ -2790,70 +2790,70 @@
     <declare-styleable name="SearchableActionKey">
         <!-- This attribute denotes the action key you wish to respond to.  Note that not
             all action keys are actually supported using this mechanism, as many of them are
-            used for typing, navigation, or system functions.  This will be added to the 
+            used for typing, navigation, or system functions.  This will be added to the
             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
-            searchable activity.  To examine the key code, use 
+            searchable activity.  To examine the key code, use
             {@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}.
-            <p>Note, in addition to the keycode, you must also provide one or more of the action 
+            <p>Note, in addition to the keycode, you must also provide one or more of the action
             specifier attributes.  <i>Required attribute.</i> -->
         <attr name="keycode" />
-        
+
         <!-- If you wish to handle an action key during normal search query entry, you
-            must define an action string here.  This will be added to the 
+            must define an action string here.  This will be added to the
             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
-            searchable activity.  To examine the string, use 
+            searchable activity.  To examine the string, use
             {@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
             <i>Optional attribute.</i> -->
         <attr name="queryActionMsg"  format="string" />
-        
+
         <!-- If you wish to handle an action key while a suggestion is being displayed <i>and
             selected</i>, there are two ways to handle this.  If <i>all</i> of your suggestions
-            can handle the action key, you can simply define the action message using this 
-            attribute.  This will be added to the 
+            can handle the action key, you can simply define the action message using this
+            attribute.  This will be added to the
             {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
-            searchable activity.  To examine the string, use 
+            searchable activity.  To examine the string, use
             {@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
             <i>Optional attribute.</i> -->
         <attr name="suggestActionMsg"  format="string" />
-        
+
         <!-- If you wish to handle an action key while a suggestion is being displayed <i>and
-            selected</i>, but you do not wish to enable this action key for every suggestion, 
+            selected</i>, but you do not wish to enable this action key for every suggestion,
             then you can use this attribute to control it on a suggestion-by-suggestion basis.
-            First, you must define a column (and name it here) where your suggestions will include 
+            First, you must define a column (and name it here) where your suggestions will include
             the action string.  Then, in your content provider, you must provide this column, and
             when desired, provide data in this column.
-            The search manager will look at your suggestion cursor, using the string 
-            provided here in order to select a column, and will use that to select a string from 
-            the cursor.  That string will be added to the 
-            {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to 
-            your searchable activity.  To examine the string, use 
-            {@link android.content.Intent#getStringExtra 
+            The search manager will look at your suggestion cursor, using the string
+            provided here in order to select a column, and will use that to select a string from
+            the cursor.  That string will be added to the
+            {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
+            your searchable activity.  To examine the string, use
+            {@link android.content.Intent#getStringExtra
             getStringExtra(SearchManager.ACTION_MSG)}.  <i>If the data does not exist for the
             selection suggestion, the action key will be ignored.</i><i>Optional attribute.</i> -->
         <attr name="suggestActionMsgColumn" format="string" />
 
     </declare-styleable>
-    
+
     <!-- ***************************************************************** -->
     <!-- Support for MapView. -->
     <!-- ***************************************************************** -->
     <eat-comment />
-    
+
     <!-- The set of attributes for a MapView. -->
     <declare-styleable name="MapView">
         <!-- Value is a string that specifies the Maps API Key to use. -->
         <attr name="apiKey" format="string" />
     </declare-styleable>
-    
+
     <!-- **************************************************************** -->
     <!-- Menu XML inflation. -->
     <!-- **************************************************************** -->
     <eat-comment />
-    
+
     <!-- Base attributes that are available to all Menu objects. -->
     <declare-styleable name="Menu">
     </declare-styleable>
-    
+
     <!-- Base attributes that are available to all groups. -->
     <declare-styleable name="MenuGroup">
 
@@ -2872,11 +2872,11 @@
             <!-- Items are alternative actions. -->
             <enum name="alternative" value="0x00040000" />
         </attr>
-        
+
         <!-- The order within the category applied to all items within this group.
              (This will be or'ed with the category attribute.) -->
         <attr name="orderInCategory" format="integer" />
-        
+
         <!-- Whether the items are capable of displaying a check mark. -->
         <attr name="checkableBehavior">
             <!-- The items are not checkable. -->
@@ -2887,7 +2887,7 @@
                  this group. -->
             <enum name="single" value="2" />
         </attr>
-                
+
         <!-- Whether the items are shown/visible. -->
         <attr name="visible" />
 
@@ -2901,7 +2901,7 @@
 
         <!-- The ID of the item. -->
         <attr name="id" />
-        
+
         <!-- The category applied to the item.
              (This will be or'ed with the orderInCategory attribute.) -->
         <attr name="menuCategory" />
@@ -2912,15 +2912,15 @@
 
         <!-- The title associated with the item. -->
         <attr name="title" format="string" />
-        
+
         <!-- The condensed title associated with the item.  This is used in situations where the
              normal title may be too long to be displayed. -->
         <attr name="titleCondensed" format="string" />
 
         <!-- The icon associated with this item.  This icon will not always be shown, so
-             the title should be sufficient in describing this item. -->        
+             the title should be sufficient in describing this item. -->
         <attr name="icon" />
-        
+
         <!-- The alphabetic shortcut key.  This is the shortcut when using a keyboard
              with alphabetic keys. -->
         <attr name="alphabeticShortcut" format="string" />
@@ -2928,14 +2928,14 @@
         <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
              keyboard. -->
         <attr name="numericShortcut" format="string" />
-        
+
         <!-- Whether the item is capable of displaying a check mark. -->
         <attr name="checkable" format="boolean" />
-        
-        <!-- Whether the item is checked.  Note that you must first have enabled checking with 
+
+        <!-- Whether the item is checked.  Note that you must first have enabled checking with
              the checkable attribute or else the check mark will not appear. -->
         <attr name="checked" />
-        
+
         <!-- Whether the item is shown/visible. -->
         <attr name="visible" />
 
@@ -2961,7 +2961,7 @@
                    with a View's attributes.  Some subclasses (e.g., EditTextPreference)
                    proxy all attributes to its EditText widget. -->
     <eat-comment />
-    
+
     <!-- Base attributes available to Preference. -->
     <declare-styleable name="Preference">
         <!-- The key to store the Preference value. -->
@@ -3090,7 +3090,7 @@
              it had previously been shown. -->
         <attr name="imeExtractExitAnimation" format="reference" />
     </declare-styleable>
-    
+
     <declare-styleable name="KeyboardView">
         <!-- Default KeyboardView style. -->
         <attr name="keyboardViewStyle" format="reference" />
@@ -3123,13 +3123,13 @@
 
         <!-- Layout resource for popup keyboards -->
         <attr name="popupLayout" format="reference" />
-        
+
         <attr name="shadowColor" />
         <attr name="shadowRadius" />
     </declare-styleable>
-    
+
     <declare-styleable name="KeyboardViewPreviewState">
-        <!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView} 
+        <!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
                 key preview background -->
         <attr name="state_long_pressable" format="boolean" />
     </declare-styleable>
@@ -3212,7 +3212,20 @@
              If not supplied, then no activity will be launched. -->
         <attr name="configure" format="string" />
     </declare-styleable>
-    
-    
+
+
+    <!-- =============================== -->
+    <!-- Accounts package class attributes -->
+    <!-- =============================== -->
+
+    <!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
+         describes an account authenticator.
+     -->
+    <declare-styleable name="AccountAuthenticator">
+        <!-- the account type this authenticator handles. -->
+        <attr name="accountType" format="string"/>
+    </declare-styleable>
+
+
 </resources>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5b5e5c2..88eab61 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -5,16 +5,16 @@
      ***************************************************************
      IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
      READ THIS BEFORE YOU MAKE ANY CHANGES
-     
+
      This file defines the binary compatibility for resources.  As such,
      you must be very careful when making changes here, or you will
      completely break backwards compatibility with old applications.
-     
+
      To avoid breaking compatibility, all new resources must be placed
      at the end of the list of resources of the same type.  Placing a resource
      in the middle of type will cause all following resources to be
      assigned new resource numbers, breaking compatibility.
-     
+
      ***************************************************************
      *************************************************************** -->
 <resources>
@@ -22,7 +22,7 @@
   <!-- We don't want to publish private symbols in android.R as part of the
        SDK.  Instead, put them here. -->
   <private-symbols package="com.android.internal" />
-    
+
   <!-- AndroidManifest.xml attributes. -->
   <eat-comment />
 
@@ -569,10 +569,10 @@
   <public type="attr" name="lineSpacingExtra" id="0x01010217" />
   <public type="attr" name="lineSpacingMultiplier" id="0x01010218" />
   <public type="attr" name="listChoiceIndicatorSingle" id="0x01010219" />
-  <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />    
+  <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
   <public type="attr" name="versionCode" id="0x0101021b" />
   <public type="attr" name="versionName" id="0x0101021c" />
-  
+
   <public type="id" name="background" id="0x01020000" />
   <public type="id" name="checkbox" id="0x01020001" />
   <public type="id" name="content" id="0x01020002" />
@@ -601,7 +601,7 @@
   <public type="id" name="button1" id="0x01020019" />
   <public type="id" name="button2" id="0x0102001a" />
   <public type="id" name="button3" id="0x0102001b" />
-  
+
   <public type="style" name="Animation" id="0x01030000" />
   <public type="style" name="Animation.Activity" id="0x01030001" />
   <public type="style" name="Animation.Dialog" id="0x01030002" />
@@ -748,7 +748,7 @@
   <public type="drawable" name="btn_plus" id="0x01080008" />
   <public type="drawable" name="btn_radio" id="0x01080009" />
   <public type="drawable" name="btn_star" id="0x0108000a" />
-  <public type="drawable" name="btn_star_big_off" id="0x0108000b" /> 
+  <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
   <public type="drawable" name="btn_star_big_on" id="0x0108000c" />
   <public type="drawable" name="button_onoff_indicator_on" id="0x0108000d" />
   <public type="drawable" name="button_onoff_indicator_off" id="0x0108000e" />
@@ -916,7 +916,7 @@
   <public type="layout" name="select_dialog_item" id="0x01090011" />
   <public type="layout" name="select_dialog_singlechoice" id="0x01090012" />
   <public type="layout" name="select_dialog_multichoice" id="0x01090013" />
-  
+
   <public type="anim" name="fade_in" id="0x010a0000" />
   <public type="anim" name="fade_out" id="0x010a0001" />
   <public type="anim" name="slide_in_left" id="0x010a0002" />
@@ -929,9 +929,9 @@
      Resources added in version 2 of the platform.
      =============================================================== -->
   <eat-comment />
-  
+
   <public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
-  
+
 <!-- ===============================================================
      Resources added in version 3 of the platform.
      =============================================================== -->
@@ -1062,7 +1062,7 @@
   <public type="id" name="stopSelectingText" id="0x01020029" />
   <!-- Menu ID to perform a "add to dictionary" operation. -->
   <public type="id" name="addToDictionary" id="0x0102002a" />
-  
+
   <public type="style" name="Theme.InputMethod" id="0x01030054" />
   <public type="style" name="Theme.NoDisplay" id="0x01030055" />
   <public type="style" name="Animation.InputMethod" id="0x01030056" />
@@ -1070,7 +1070,7 @@
   <public type="style" name="ButtonBar" id="0x01030058" />
   <public type="style" name="Theme.Panel" id="0x01030059" />
   <public type="style" name="Theme.Light.Panel" id="0x0103005a" />
-  
+
   <public type="string" name="dialog_alert_title" id="0x01040014" />
   <public type="string" name="VideoView_error_text_invalid_progressive_playback" id="0x01040015" />
 
@@ -1103,4 +1103,10 @@
   <public type="drawable" name="stat_sys_vp_phone_call" id="0x0108022d" />
   <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x0108022e" />
 
+<!-- ===============================================================
+     Resources added in version 5 of the platform.
+     =============================================================== -->
+  <eat-comment />
+
+  <public type="attr" name="accountType" id="0x0101026c" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c35676c..21e9d97 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -129,7 +129,7 @@
     <string name="RestrictedOnNormal">Voice/SMS service is blocked.</string>
     <!-- Displayed to tell the user that all voice service is blocked by access control. -->
     <string name="RestrictedOnAll">All voice/SMS services are blocked.</string>
-    
+
     <!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
     <!-- Example: Service was enabled for: Voice, Data -->
     <string name="serviceClassVoice">Voice</string>
@@ -206,6 +206,13 @@
     <!-- Displayed when a request failed because there are too many requests right now. -->
     <string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
 
+    <!-- Account notifications --> <skip />
+    <!-- A notification is shown when the AccountManager is unable to
+    supply an auth token without prompting the user to re-enter the
+    password.  This is the text that will scroll through the
+    notification bar (will be seen by the user as he uses another application). -->
+    <string name="notification_title">Sign-in error</string>
+
     <!-- Sync notifications --> <skip />
     <!-- A notification is shown when there is a sync error.  This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
     <string name="contentServiceSync">Sync</string>
@@ -276,7 +283,7 @@
 
     <!-- Label for the Android system components when they are shown to the user. -->
     <string name="android_system_label">Android System</string>
-    
+
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -776,7 +783,7 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readFrameBuffer">read frame buffer</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readFrameBuffer">Allows application to use
+    <string name="permdesc_readFrameBuffer">Allows application to 
         read the content of the frame buffer.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1302,7 +1309,7 @@
 
     <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
     <string name="save_password_label">Confirm</string>
-    
+
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
@@ -1330,8 +1337,8 @@
     <string name="menu_delete_shortcut_label">delete</string>
 
     <!-- Strings used for search bar --><skip />
-    
-    <!-- This is the default button label in the system-wide search UI. 
+
+    <!-- This is the default button label in the system-wide search UI.
          It is also used by the home screen's search "widget". It should be short -->
     <string name="search_go">Search</string>
 
@@ -1393,7 +1400,7 @@
         <item quantity="one">tomorrow</item>
         <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
     </plurals>
-    
+
     <!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
     <plurals name="abbrev_num_seconds_ago">
         <item quantity="one">1 sec ago</item>
@@ -1521,7 +1528,7 @@
     <!-- Numeric form of the day. Example: "12/31/2007" -->
     <string name="numeric_date">"<xliff:g id="month" example="12">%m</xliff:g>/<xliff:g id="day" example="31">%d</xliff:g>/<xliff:g id="year" example="2008">%Y</xliff:g>"</string>
 
-    <!-- Format indicating a range of time, from a time on one day to a time on another day. 
+    <!-- Format indicating a range of time, from a time on one day to a time on another day.
          Example: "Mon, Dec 31, 2007, 8am - Tue, Jan 1, 2008, 5pm" -->
     <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="weekday1" example="Monday">%1$s</xliff:g>, <xliff:g id="date1" example="December 31, 2007">%2$s</xliff:g>, <xliff:g id="time1" example="8am">%3$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Tuesday">%4$s</xliff:g>, <xliff:g id="date2" example="January 1, 2008">%5$s</xliff:g>, <xliff:g id="time2" example="5pm">%6$s</xliff:g>"</string>
 
@@ -1529,7 +1536,7 @@
          Example: "Mon, Dec 31, 2007 - Tue, Jan 1, 2008" -->
     <string name="wday1_date1_wday2_date2">"<xliff:g id="weekday1" example="Monday">%1$s</xliff:g>, <xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Thursday">%4$s</xliff:g>, <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>"</string>
 
-    <!-- Format indicating a range of time, from a time on one day to a time on another day. 
+    <!-- Format indicating a range of time, from a time on one day to a time on another day.
          Example: "Dec 31, 2007, 8am - Jan 1, 2008, 5pm" -->
     <string name="date1_time1_date2_time2">"<xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g>, <xliff:g id="time1" example="8am">%3$s</xliff:g> \u2013 <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>, <xliff:g id="time2" example="5pm">%6$s</xliff:g>"</string>
 
@@ -2226,7 +2233,7 @@
     <string name="usb_storage_button_mount">Mount</string>
     <!-- See USB_STORAGE.   This is the button text to ignore the plugging in of the phone.. -->
     <string name="usb_storage_button_unmount">Don\'t mount</string>
-    <!-- See USB_STORAGE_DIALOG.  If there was an error mounting, this is the text. --> 
+    <!-- See USB_STORAGE_DIALOG.  If there was an error mounting, this is the text. -->
     <string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
     <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across.  This is the title -->
     <string name="usb_storage_notification_title">USB connected</string>
@@ -2247,7 +2254,7 @@
     <string name="usb_storage_stop_button_mount">Turn Off</string>
     <!-- See USB_STORAGE_STOP.   This is the button text to cancel stoping usb storage. -->
     <string name="usb_storage_stop_button_unmount">Cancel</string>
-    <!-- See USB_STORAGE_STOP_DIALOG.  If there was an error stopping, this is the text. --> 
+    <!-- See USB_STORAGE_STOP_DIALOG.  If there was an error stopping, this is the text. -->
     <string name="usb_storage_stop_error_message">We've encountered a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
 
     <!-- External media format dialog strings -->
@@ -2268,10 +2275,10 @@
 
     <!-- Title of the pop-up dialog in which the user switches input method components. -->
     <string name="select_input_method">Select Input Method</string>
-    
+
     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
-    
+
     <string name="candidates_style"><u>candidates</u></string>
 
     <!-- External media notification strings -->
@@ -2318,23 +2325,23 @@
 
     <!-- Long label for a button on a full-screen input method for the "Go" action. -->
     <string name="ime_action_go">Go</string>
-    
+
     <!-- Long label for a button on a full-screen input method for the "Search" action. -->
     <string name="ime_action_search">Search</string>
-    
+
     <!-- Long label for a button on a full-screen input method for the "Send" action. -->
     <string name="ime_action_send">Send</string>
-    
+
     <!-- Long label for a button on a full-screen input method for the "Next" action. -->
     <string name="ime_action_next">Next</string>
-    
+
     <!-- Long label for a button on a full-screen input method for the "Done" action. -->
     <string name="ime_action_done">Done</string>
-    
+
     <!-- Long label for a button on a full-screen input method for an unknown action. -->
     <string name="ime_action_default">Execute</string>
-    
-    <!-- Strings for search suggestions. These are going here because they are referenced by both 
+
+    <!-- Strings for search suggestions. These are going here because they are referenced by both
          ContactsProvider and GoogleContactsProvider -->
     <skip />
 
@@ -2347,7 +2354,7 @@
 
     <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale pairs.  This is used at startup to set a default locale by checking the system property ro.carrier for the carrier-id and searching through this array -->
     <string-array translatable="false" name="carrier_locales">
-    </string-array>    
+    </string-array>
 </resources>
 
 
diff --git a/docs/html/guide/developing/tools/ddms.jd b/docs/html/guide/developing/tools/ddms.jd
index fa04216..f55940d 100644
--- a/docs/html/guide/developing/tools/ddms.jd
+++ b/docs/html/guide/developing/tools/ddms.jd
@@ -1,7 +1,7 @@
-page.title=Using Dalvik Debug Monitor Service (DDMS)
+page.title=Using the Dalvik Debug Monitor
 @jd:body
 
-<p>Android ships with a debugging tool called the Dalvik Debug Monitor Service (DDMS),
+<p>Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS),
     which provides port-forwarding services, screen capture on the device, thread
     and heap information on the device, logcat, process, and radio state information,
     incoming call and SMS spoofing, location data spoofing, and more. This page
@@ -106,7 +106,7 @@
         </ul>
     </li>
     <li> <strong>utime</strong> - cumulative time spent executing user code, in &quot;jiffies&quot; (usually
-        10ms). Only available under Linux. </li>
+        10ms). </li>
     <li> <strong>stime</strong> - cumulative time spent executing system code, in &quot;jiffies&quot;  (usually
         10ms). </li>
     <li> <strong>Name</strong> - the name of the thread</li>
@@ -214,14 +214,15 @@
 
 <h2 id="screen-capture">Screen Capture</h2>
 <p>You can capture screen images on the device or emulator by selecting <strong>Device</strong>
-    &gt; <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.</p>
+    &gt; <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.
+	Be sure to select a device first.</p>
 
 <h2 id="exploring-processes">Exploring Processes</h2>
 <p>You can see the output of <code>ps -x</code> for a specific VM by selecting <strong>Device</strong>
     &gt; <strong>Show process status</strong>... in the menu bar.</p>
 
 <h2 id="cause-a-gc-to-occur">Cause a GC to Occur</h2>
-<p>Cause garbage collection to occury by pressing the trash can button on the toolbar. </p>
+<p>Cause garbage collection to occur in the selected application by pressing the trash can button on the toolbar. </p>
 
 <h2 id="running-dumpsys-and-dumpstate">Running Dumpsys and Dumpstate on the Device (logcat)<a name="logcat" id="logcat"></a> </h2>
 <ul>
@@ -239,7 +240,7 @@
 
 <h2 id="stop-a-vitrual-machine">Stop a Virtual Machine </h2>
 <p>You can stop a virtual machine by selecting <strong>Actions</strong> &gt; <strong>Halt
-VM</strong>. Pressing this  button causes the VM to call <code>System.exit(1)</code>.</p>
+VM</strong>. Pressing this button causes the VM to call <code>Runtime.halt(1)</code>.</p>
 
 <h2 id="known-issues" style="color:#FF0000">Known issues with DDMS </h2>
 <p>DDMS has the following known limitations:</p>
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 78bef91..0304309 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -98,6 +98,7 @@
 
 private:
     static int startReg(JNIEnv* env);
+    int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
 
     Vector<JavaVMOption> mOptions;
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index b56221f..a4050b3 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -652,6 +652,7 @@
     }
 
     status_t ret = NO_ERROR;
+    
     if (stream == AudioSystem::VOICE_CALL ||
         stream == AudioSystem::BLUETOOTH_SCO) {
         float hwValue;
@@ -668,7 +669,13 @@
         mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
         ret = mAudioHardware->setVoiceVolume(hwValue);
         mHardwareStatus = AUDIO_HW_IDLE;
+        
     }
+    
+    mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
 
     mHardwareMixerThread->setStreamVolume(stream, value);
 #ifdef WITH_A2DP
diff --git a/libs/surfaceflinger/LayerScreenshot.cpp b/libs/surfaceflinger/LayerScreenshot.cpp
new file mode 100644
index 0000000..fb7b585
--- /dev/null
+++ b/libs/surfaceflinger/LayerScreenshot.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerScreenshot.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerScreenshot::typeInfo = LayerBase::typeInfo | 0x20;
+const char* const LayerScreenshot::typeID = "LayerScreenshot";
+
+// ---------------------------------------------------------------------------
+
+LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display)
+    : LayerBase(flinger, display), mReply(0)
+{
+}
+
+LayerScreenshot::~LayerScreenshot()
+{
+}
+
+void LayerScreenshot::onDraw(const Region& clip) const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    copybit_image_t dst;
+    hw.getDisplaySurface(&dst);
+    if (dst.base != 0) {
+        uint8_t const* src = (uint8_t const*)(intptr_t(dst.base) + dst.offset); 
+        const int fbWidth = dst.w;
+        const int fbHeight = dst.h;
+        const int fbFormat = dst.format;
+
+        int x = mTransformedBounds.left;
+        int y = mTransformedBounds.top;
+        int w = mTransformedBounds.width();
+        int h = mTransformedBounds.height();
+        Parcel* const reply = mReply;
+        if (reply) {
+            const size_t Bpp = bytesPerPixel(fbFormat);
+            const size_t size = w * h * Bpp;
+            int32_t cfg = SkBitmap::kNo_Config;
+            switch (fbFormat) {
+                case PIXEL_FORMAT_RGBA_4444: cfg = SkBitmap::kARGB_4444_Config; break;
+                case PIXEL_FORMAT_RGBA_8888: cfg = SkBitmap::kARGB_8888_Config; break;
+                case PIXEL_FORMAT_RGB_565:   cfg = SkBitmap::kRGB_565_Config; break;
+                case PIXEL_FORMAT_A_8:       cfg = SkBitmap::kA8_Config; break;
+            }
+            reply->writeInt32(0);
+            reply->writeInt32(cfg);
+            reply->writeInt32(w);
+            reply->writeInt32(h);
+            reply->writeInt32(w * Bpp);
+            void* data = reply->writeInplace(size);
+            if (data) {
+                uint8_t* d = (uint8_t*)data;
+                uint8_t const* s = src + (x + y*fbWidth) * Bpp;
+                if (w == fbWidth) {
+                    memcpy(d, s, w*h*Bpp);   
+                } else {
+                    for (int y=0 ; y<h ; y++) {
+                        memcpy(d, s, w*Bpp);
+                        d += w*Bpp;
+                        s += fbWidth*Bpp;
+                    }
+                }
+            }
+        }
+    }
+    mCV.broadcast();
+}
+
+void LayerScreenshot::takeScreenshot(Mutex& lock, Parcel* reply)
+{
+    mReply = reply;
+    mCV.wait(lock);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 167a59b..54b33ce 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <math.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
index 0f4b647..4225e67 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/utils/Parcel.cpp
@@ -950,14 +950,13 @@
             return 0;
         }
     }
-    
     for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
         h->data[i] = dup(readFileDescriptor());
         if (h->data[i] < 0) err = BAD_VALUE;
     }
-    
+
     err = read(h->data + numFds, sizeof(int)*numInts);
-    
+
     if (err != NO_ERROR) {
         if (alloc == 0) {
             free(h);
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
index 89aa874..2132d22 100644
--- a/libs/utils/ZipFile.cpp
+++ b/libs/utils/ZipFile.cpp
@@ -94,10 +94,10 @@
     }
     mZipFp = fopen(zipFileName, openflags);
     if (mZipFp == NULL) {
-		int err = errno;
-		LOGD("fopen failed: %d\n", err);
+        int err = errno;
+        LOGD("fopen failed: %d\n", err);
         return errnoToStatus(err);
-	}
+    }
 
     status_t result;
     if (!newArchive) {
@@ -221,8 +221,8 @@
 
     buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
     if (buf == NULL) {
-		LOGD("Failure allocating %d bytes for EOCD search",
-			 EndOfCentralDir::kMaxEOCDSearch);
+        LOGD("Failure allocating %d bytes for EOCD search",
+             EndOfCentralDir::kMaxEOCDSearch);
         result = NO_MEMORY;
         goto bail;
     }
@@ -235,7 +235,7 @@
         readAmount = (long) fileLength;
     }
     if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
-		LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+        LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
         result = UNKNOWN_ERROR;
         goto bail;
     }
@@ -265,9 +265,9 @@
     /* extract eocd values */
     result = mEOCD.readBuf(buf + i, readAmount - i);
     if (result != NO_ERROR) {
-		LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+        LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
         goto bail;
-	}
+    }
     //mEOCD.dump();
 
     if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
@@ -293,8 +293,8 @@
      * we're hoping to preserve.
      */
     if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
-		LOGD("Failure seeking to central dir offset %ld\n",
-			 mEOCD.mCentralDirOffset);
+        LOGD("Failure seeking to central dir offset %ld\n",
+             mEOCD.mCentralDirOffset);
         result = UNKNOWN_ERROR;
         goto bail;
     }
@@ -743,61 +743,61 @@
     const void* data, size_t size, unsigned long* pCRC32)
 {
     status_t result = NO_ERROR;
-	const size_t kBufSize = 32768;
-	unsigned char* inBuf = NULL;
-	unsigned char* outBuf = NULL;
-	z_stream zstream;
+    const size_t kBufSize = 32768;
+    unsigned char* inBuf = NULL;
+    unsigned char* outBuf = NULL;
+    z_stream zstream;
     bool atEof = false;     // no feof() aviailable yet
-	unsigned long crc;
-	int zerr;
+    unsigned long crc;
+    int zerr;
 
-	/*
-	 * Create an input buffer and an output buffer.
-	 */
-	inBuf = new unsigned char[kBufSize];
-	outBuf = new unsigned char[kBufSize];
-	if (inBuf == NULL || outBuf == NULL) {
-		result = NO_MEMORY;
-		goto bail;
-	}
+    /*
+     * Create an input buffer and an output buffer.
+     */
+    inBuf = new unsigned char[kBufSize];
+    outBuf = new unsigned char[kBufSize];
+    if (inBuf == NULL || outBuf == NULL) {
+        result = NO_MEMORY;
+        goto bail;
+    }
 
-	/*
-	 * Initialize the zlib stream.
-	 */
-	memset(&zstream, 0, sizeof(zstream));
-	zstream.zalloc = Z_NULL;
-	zstream.zfree = Z_NULL;
-	zstream.opaque = Z_NULL;
-	zstream.next_in = NULL;
-	zstream.avail_in = 0;
-	zstream.next_out = outBuf;
-	zstream.avail_out = kBufSize;
-	zstream.data_type = Z_UNKNOWN;
+    /*
+     * Initialize the zlib stream.
+     */
+    memset(&zstream, 0, sizeof(zstream));
+    zstream.zalloc = Z_NULL;
+    zstream.zfree = Z_NULL;
+    zstream.opaque = Z_NULL;
+    zstream.next_in = NULL;
+    zstream.avail_in = 0;
+    zstream.next_out = outBuf;
+    zstream.avail_out = kBufSize;
+    zstream.data_type = Z_UNKNOWN;
 
-	zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
-		Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-	if (zerr != Z_OK) {
-		result = UNKNOWN_ERROR;
-		if (zerr == Z_VERSION_ERROR) {
-			LOGE("Installed zlib is not compatible with linked version (%s)\n",
-				ZLIB_VERSION);
-		} else {
-			LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
-		}
-		goto bail;
-	}
+    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+    if (zerr != Z_OK) {
+        result = UNKNOWN_ERROR;
+        if (zerr == Z_VERSION_ERROR) {
+            LOGE("Installed zlib is not compatible with linked version (%s)\n",
+                ZLIB_VERSION);
+        } else {
+            LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+        }
+        goto bail;
+    }
 
- 	crc = crc32(0L, Z_NULL, 0);
+    crc = crc32(0L, Z_NULL, 0);
 
-	/*
-	 * Loop while we have data.
-	 */
-	do {
-		size_t getSize;
-		int flush;
+    /*
+     * Loop while we have data.
+     */
+    do {
+        size_t getSize;
+        int flush;
 
-		/* only read if the input buffer is empty */
-		if (zstream.avail_in == 0 && !atEof) {
+        /* only read if the input buffer is empty */
+        if (zstream.avail_in == 0 && !atEof) {
             LOGV("+++ reading %d bytes\n", (int)kBufSize);
             if (data) {
                 getSize = size > kBufSize ? kBufSize : size;
@@ -817,54 +817,54 @@
                 atEof = true;
             }
 
-			crc = crc32(crc, inBuf, getSize);
+            crc = crc32(crc, inBuf, getSize);
 
-			zstream.next_in = inBuf;
-			zstream.avail_in = getSize;
-		}
+            zstream.next_in = inBuf;
+            zstream.avail_in = getSize;
+        }
 
-		if (atEof)
-			flush = Z_FINISH;       /* tell zlib that we're done */
-		else
-			flush = Z_NO_FLUSH;     /* more to come! */
+        if (atEof)
+            flush = Z_FINISH;       /* tell zlib that we're done */
+        else
+            flush = Z_NO_FLUSH;     /* more to come! */
 
-		zerr = deflate(&zstream, flush);
-		if (zerr != Z_OK && zerr != Z_STREAM_END) {
-			LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
-			result = UNKNOWN_ERROR;
-			goto z_bail;
-		}
+        zerr = deflate(&zstream, flush);
+        if (zerr != Z_OK && zerr != Z_STREAM_END) {
+            LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+            result = UNKNOWN_ERROR;
+            goto z_bail;
+        }
 
-		/* write when we're full or when we're done */
-		if (zstream.avail_out == 0 ||
-			(zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
-		{
-			LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+        /* write when we're full or when we're done */
+        if (zstream.avail_out == 0 ||
+            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+        {
+            LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
             if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
                 (size_t)(zstream.next_out - outBuf))
             {
-				LOGD("write %d failed in deflate\n",
+                LOGD("write %d failed in deflate\n",
                     (int) (zstream.next_out - outBuf));
-				goto z_bail;
-			}
+                goto z_bail;
+            }
 
-			zstream.next_out = outBuf;
-			zstream.avail_out = kBufSize;
-		}
-	} while (zerr == Z_OK);
+            zstream.next_out = outBuf;
+            zstream.avail_out = kBufSize;
+        }
+    } while (zerr == Z_OK);
 
-	assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
+    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
 
-	*pCRC32 = crc;
+    *pCRC32 = crc;
 
 z_bail:
-	deflateEnd(&zstream);        /* free up any allocated structures */
+    deflateEnd(&zstream);        /* free up any allocated structures */
 
 bail:
-	delete[] inBuf;
-	delete[] outBuf;
+    delete[] inBuf;
+    delete[] outBuf;
 
-	return result;
+    return result;
 }
 
 /*
@@ -1206,7 +1206,7 @@
 
 /*
  * ===========================================================================
- *		ZipFile::EndOfCentralDir
+ *      ZipFile::EndOfCentralDir
  * ===========================================================================
  */
 
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 53e46b7..2ce1273 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -36,11 +36,11 @@
  * coordinate into a (partial) address.  The amount of detail in a
  * reverse geocoded location description may vary, for example one
  * might contain the full street address of the closest building, while
- * another might contain only a city name and postal code. 
+ * another might contain only a city name and postal code.
  *
  * The Geocoder class requires a backend service that is not included in
- * the core android framework. The Geocoder query methods will return an
- * empty list if there no backend service in the platform. 
+ * the core android framework.  The Geocoder query methods will return an
+ * empty list if there no backend service in the platform.
  */
 public final class Geocoder {
     private static final String TAG = "Geocoder";
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java
index 2a8be57..33ebce7 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/location/java/com/android/internal/location/GpsXtraDownloader.java
@@ -64,6 +64,7 @@
         
         if (count == 0) {
             Log.e(TAG, "No XTRA servers were specified in the GPS configuration");
+            return;
         } else {
             mXtraServers = new String[count];
             count = 0;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index ae3e181..c0cd5e3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -269,10 +269,14 @@
     private boolean mDefaultRingtoneSet;
     /** Whether the scanner has set a default sound for the notification ringtone. */
     private boolean mDefaultNotificationSet;
+    /** Whether the scanner has set a default sound for the alarm ringtone. */
+    private boolean mDefaultAlarmSet;
     /** The filename for the default sound for the ringer ringtone. */
     private String mDefaultRingtoneFilename;
     /** The filename for the default sound for the notification ringtone. */
     private String mDefaultNotificationFilename;
+    /** The filename for the default sound for the alarm ringtone. */
+    private String mDefaultAlarmAlertFilename;
     /**
      * The prefix for system properties that define the default sound for
      * ringtones. Concatenate the name of the setting from Settings
@@ -331,6 +335,8 @@
                 + Settings.System.RINGTONE);
         mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
                 + Settings.System.NOTIFICATION_SOUND);
+        mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+                + Settings.System.ALARM_ALERT);
     }
     
     private MyMediaScannerClient mClient = new MyMediaScannerClient();
@@ -710,6 +716,12 @@
                     setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
                     mDefaultRingtoneSet = true;
                 }
+            } else if (alarms && !mDefaultAlarmSet) {
+                if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+                        doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+                    setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+                    mDefaultAlarmSet = true;
+                }
             }
             
             return result;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8f05cec..70d29d2 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -122,8 +122,9 @@
      * current ringtone, which will be used to show a checkmark next to the item
      * for this {@link Uri}. If showing an item for "Default" (@see
      * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of
-     * {@link System#DEFAULT_RINGTONE_URI} or
-     * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" item
+     * {@link System#DEFAULT_RINGTONE_URI},
+     * {@link System#DEFAULT_NOTIFICATION_URI}, or
+     * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" item
      * checked.
      * 
      * @see #ACTION_RINGTONE_PICKER
@@ -134,8 +135,9 @@
     /**
      * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
      * ringtone to play when the user attempts to preview the "Default"
-     * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI} or
-     * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" point to
+     * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI},
+     * {@link System#DEFAULT_NOTIFICATION_URI}, or
+     * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" point to
      * the current sound for the given default sound type. If you are showing a
      * ringtone picker for some other type of sound, you are free to provide any
      * {@link Uri} here.
@@ -163,8 +165,9 @@
      * <p>
      * It will be one of:
      * <li> the picked ringtone,
-     * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI} or
-     * {@link System#DEFAULT_NOTIFICATION_URI} if the default was chosen,
+     * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI},
+     * {@link System#DEFAULT_NOTIFICATION_URI}, or
+     * {@link System#DEFAULT_ALARM_ALERT_URI} if the default was chosen,
      * <li> null if the "Silent" item was picked.
      * 
      * @see #ACTION_RINGTONE_PICKER
@@ -624,7 +627,8 @@
      * 
      * @param context A context used for querying.
      * @param type The type whose default sound should be returned. One of
-     *            {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+     *            {@link #TYPE_ALARM}.
      * @return A {@link Uri} pointing to the default sound for the sound type.
      * @see #setActualDefaultRingtoneUri(Context, int, Uri)
      */
@@ -640,7 +644,8 @@
      * 
      * @param context A context used for querying.
      * @param type The type whose default sound should be set. One of
-     *            {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+     *            {@link #TYPE_ALARM}.
      * @param ringtoneUri A {@link Uri} pointing to the default sound to set.
      * @see #getActualDefaultRingtoneUri(Context, int)
      */
@@ -655,6 +660,8 @@
             return Settings.System.RINGTONE;
         } else if ((type & TYPE_NOTIFICATION) != 0) {
             return Settings.System.NOTIFICATION_SOUND;
+        } else if ((type & TYPE_ALARM) != 0) {
+            return Settings.System.ALARM_ALERT;
         } else {
             return null;
         }
@@ -674,8 +681,9 @@
      * Returns the type of a default {@link Uri}.
      * 
      * @param defaultRingtoneUri The default {@link Uri}. For example,
-     *            {@link System#DEFAULT_RINGTONE_URI} or
-     *            {@link System#DEFAULT_NOTIFICATION_URI}.
+     *            {@link System#DEFAULT_RINGTONE_URI},
+     *            {@link System#DEFAULT_NOTIFICATION_URI}, or
+     *            {@link System#DEFAULT_ALARM_ALERT_URI}.
      * @return The type of the defaultRingtoneUri, or -1.
      */
     public static int getDefaultType(Uri defaultRingtoneUri) {
@@ -685,6 +693,8 @@
             return TYPE_RINGTONE;
         } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
             return TYPE_NOTIFICATION;
+        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_ALARM_ALERT_URI)) {
+            return TYPE_ALARM;
         } else {
             return -1;
         }
@@ -704,6 +714,8 @@
             return Settings.System.DEFAULT_RINGTONE_URI;
         } else if ((type & TYPE_NOTIFICATION) != 0) {
             return Settings.System.DEFAULT_NOTIFICATION_URI;
+        } else if ((type & TYPE_ALARM) != 0) {
+            return Settings.System.DEFAULT_ALARM_ALERT_URI;
         } else {
             return null;
         }
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 3620494..8ee0cbd 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -3,31 +3,32 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_MediaPlayer.cpp \
-	android_media_MediaRecorder.cpp \
-	android_media_MediaScanner.cpp \
-	android_media_MediaMetadataRetriever.cpp \
-	android_media_AmrInputStream.cpp \
-	android_media_ResampleInputStream.cpp
+    android_media_MediaPlayer.cpp \
+    android_media_MediaRecorder.cpp \
+    android_media_MediaScanner.cpp \
+    android_media_MediaMetadataRetriever.cpp \
+    android_media_AmrInputStream.cpp \
+    android_media_ResampleInputStream.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libopencoreplayer \
-	libopencoreauthor \
-	libandroid_runtime \
-	libnativehelper \
-	libcutils \
-	libutils \
-	libmedia \
-	libsgl \
-	libui
+    libopencore_player \
+    libopencore_author \
+    libomx_amrenc_sharedlibrary \
+    libandroid_runtime \
+    libnativehelper \
+    libcutils \
+    libutils \
+    libmedia \
+    libsgl \
+    libui
 
 LOCAL_STATIC_LIBRARIES :=
 
 LOCAL_C_INCLUDES += \
-	external/tremor/Tremor \
-	$(PV_INCLUDES) \
-	$(JNI_H_INCLUDE) \
-	$(call include-path-for, corecg graphics)
+    external/tremor/Tremor \
+    $(PV_INCLUDES) \
+    $(JNI_H_INCLUDE) \
+    $(call include-path-for, corecg graphics)
 
 LOCAL_CFLAGS +=
 
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index 978c110..51cb6c7 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -74,7 +74,7 @@
     encodeProps.iInNumChannels = 1;
     encodeProps.iInInterleaveMode = TEncodeProperties::EINTERLEAVE_LR;
     encodeProps.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2;
-    encodeProps.iBitStreamFormatIf2 = false;
+    encodeProps.iBitStreamFormat = false;
     encodeProps.iAudioObjectType = 0;
     encodeProps.iOutSamplingRate = encodeProps.iInSamplingRate;
     encodeProps.iOutNumChannels = encodeProps.iInNumChannels;
diff --git a/media/libdrm/mobile2/include/rights/RoManager.h b/media/libdrm/mobile2/include/rights/RoManager.h
index cf398b3..71e9eef 100644
--- a/media/libdrm/mobile2/include/rights/RoManager.h
+++ b/media/libdrm/mobile2/include/rights/RoManager.h
@@ -64,12 +64,6 @@
     vector<Ro*> getAllRo();
 
     /**
-     * Get the private key of the device.
-     * @return the private key.
-     */
-    const string& getDevicePrivateKey() const;
-
-    /**
      * Get ro which contained rights of specific content.
      * @param contentID the specific id of content.
      * @return NULL if not fount otherwise the related ro.
diff --git a/media/libdrm/mobile2/src/rights/RoManager.cpp b/media/libdrm/mobile2/src/rights/RoManager.cpp
index 848c2ba..a115d21 100644
--- a/media/libdrm/mobile2/src/rights/RoManager.cpp
+++ b/media/libdrm/mobile2/src/rights/RoManager.cpp
@@ -121,9 +121,3 @@
     return true;
 }
 
-/** see RoManager.h */
-const string& RoManager::getDevicePrivateKey() const
-{
-    string pk;
-    return pk;
-}
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f710921..f7f2490 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,28 +7,28 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-	MediaRecorderClient.cpp \
-	MediaPlayerService.cpp \
-	MetadataRetrieverClient.cpp \
-	VorbisPlayer.cpp \
-	MidiFile.cpp
+    MediaRecorderClient.cpp \
+    MediaPlayerService.cpp \
+    MetadataRetrieverClient.cpp \
+    VorbisPlayer.cpp \
+    MidiFile.cpp
 
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
 LOCAL_LDLIBS += -ldl -lpthread
 endif
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	libvorbisidec \
-	libsonivox \
-	libopencoreplayer \
-	libopencoreauthor \
-	libmedia \
-	libandroid_runtime
+    libcutils \
+    libutils \
+    libvorbisidec \
+    libsonivox \
+    libopencore_player \
+    libopencore_author \
+    libmedia \
+    libandroid_runtime
 
 LOCAL_C_INCLUDES := external/tremor/Tremor \
-	$(call include-path-for, graphics corecg)
+    $(call include-path-for, graphics corecg)
 
 LOCAL_MODULE:= libmediaplayerservice
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 31eecac..8ef0dc6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -105,7 +105,11 @@
 
 sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
 {
+#ifndef NO_OPENCORE
     sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+#else
+    sp<MediaRecorderClient> recorder = NULL;
+#endif
     LOGV("Create new media recorder client from pid %d", pid);
     return recorder;
 }
@@ -532,10 +536,12 @@
 {
     sp<MediaPlayerBase> p;
     switch (playerType) {
+#ifndef NO_OPENCORE
         case PV_PLAYER:
             LOGV(" create PVPlayer");
             p = new PVPlayer();
             break;
+#endif
         case SONIVOX_PLAYER:
             LOGV(" create MidiFile");
             p = new MidiFile();
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a320bd5..6cb4a34 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -49,7 +49,11 @@
     mThumbnail = NULL;
     mAlbumArt = NULL;
 
+#ifndef NO_OPENCORE
     mRetriever = new PVMetadataRetriever();
+#else
+    mRetriever = NULL;
+#endif
     if (mRetriever == NULL) {
         LOGE("failed to initialize the retriever");
     }
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
index 5fb6608..33b4c97 100644
--- a/packages/SettingsProvider/etc/bookmarks.xml
+++ b/packages/SettingsProvider/etc/bookmarks.xml
@@ -39,10 +39,12 @@
         package="com.android.calendar"
         class="com.android.calendar.LaunchActivity"
         shortcut="l" />
+<!--
     <bookmark
         package="com.google.android.apps.maps"
         class="com.google.android.maps.MapsActivity"
         shortcut="m" />
+-->
     <bookmark
         package="com.android.music"
         class="com.android.music.MusicBrowserActivity"
@@ -55,4 +57,4 @@
         package="com.google.android.youtube"
         class="com.google.android.youtube.HomePage"
         shortcut="y" />
-</bookmarks>
\ No newline at end of file
+</bookmarks>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b9d567c..28e5f9c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -56,7 +56,7 @@
  * Database helper class for {@link SettingsProvider}.
  * Mostly just has a bit {@link #onCreate} to initialize the database.
  */
-class DatabaseHelper extends SQLiteOpenHelper {
+public class DatabaseHelper extends SQLiteOpenHelper {
     /**
      * Path to file containing default bookmarks, relative to ANDROID_ROOT.
      */
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6f430c4..6d90001 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -43,7 +43,7 @@
     private static final String TABLE_FAVORITES = "favorites";
     private static final String TABLE_OLD_FAVORITES = "old_favorites";
 
-    private DatabaseHelper mOpenHelper;
+    protected DatabaseHelper mOpenHelper;
 
     /**
      * Decode a content URL into the table, projection, and arguments
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index df599c7..de7b1d7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -17,13 +17,15 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.os.Bundle;
-import android.os.Debug;
 import android.text.TextUtils;
 import android.net.Uri;
+import android.accounts.Account;
 
 import java.util.ArrayList;
 import java.util.Calendar;
 
+import com.google.android.collect.Lists;
+
 /**
  * A service to handle various intents asynchronously.
  */
@@ -31,7 +33,8 @@
     private static final String TAG = "Sync";
 
     private static final String[] sAccountProjection =
-            new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
+            new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT,
+                    SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE};
 
     /** How often to refresh the subscriptions, in milliseconds */
     private static final long SUBSCRIPTION_REFRESH_INTERVAL = 1000L * 60 * 60 * 24; // one day
@@ -56,10 +59,10 @@
         if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
             boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
             if (fromTrustedServer) {
-                String account = intent.getStringExtra("account");
+                String accountName = intent.getStringExtra("account");
                 String token = intent.getStringExtra("message_token");
 
-                if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
+                if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(token)) {
                     if (Config.LOGD) {
                         Log.d(TAG, "Ignoring malformed tickle -- missing account or token.");
                     }
@@ -68,10 +71,10 @@
 
                 if (Config.LOGD) {
                     Log.d(TAG, "Received network tickle for "
-                            + account + " - " + token);
+                            + accountName + " - " + token);
                 }
 
-                handleTickle(this, account, token);
+                handleTickle(this, accountName, token);
             } else {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "Ignoring tickle -- not from trusted server.");
@@ -103,20 +106,22 @@
         alarmManager.set(AlarmManager.RTC, when, pendingIntent);
     }
 
-    private void handleTickle(Context context, String account, String feed) {
+    private void handleTickle(Context context, String accountName, String feed) {
         Cursor c = null;
         Sync.Settings.QueryMap syncSettings =
                 new Sync.Settings.QueryMap(context.getContentResolver(),
                         false /* don't keep updated */,
                         null /* not needed since keep updated is false */);
         final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? "
+                + "and " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "= ? "
                 + "and " + SubscribedFeeds.Feeds.FEED + "= ?";
         try {
+            // TODO(fredq) fix the hardcoded type
             c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
-                    null, where, new String[]{account, feed}, null);
+                    null, where, new String[]{accountName, "com.google.GAIA", feed}, null);
             if (c.getCount() == 0) {
                 Log.w(TAG, "received tickle for non-existent feed: "
-                        + "account " + account + ", feed " + feed);
+                        + "account " + accountName + ", feed " + feed);
                 EventLog.writeEvent(LOG_TICKLE, "unknown");
             }
             while (c.moveToNext()) {
@@ -131,7 +136,8 @@
                 }
                 Uri uri = Uri.parse("content://" + authority);
                 Bundle extras = new Bundle();
-                extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+                extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT,
+                        new Account(accountName, "com.google.GAIA"));
                 extras.putString("feed", feed);
                 context.getContentResolver().startSync(uri, extras);
             }
@@ -151,31 +157,35 @@
      */
     private void handleRefreshAlarm(Context context) {
         // retrieve the list of accounts from the subscribed feeds
-        ArrayList<String> accounts = new ArrayList<String>();
+        ArrayList<Account> accounts = Lists.newArrayList();
         ContentResolver contentResolver = context.getContentResolver();
         Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
                 sAccountProjection, null, null, null);
-        while (c.moveToNext()) {
-            String account = c.getString(0);
-            if (TextUtils.isEmpty(account)) {
-                continue;
+        try {
+            while (c.moveToNext()) {
+                String accountName = c.getString(0);
+                String accountType = c.getString(1);
+                accounts.add(new Account(accountName, accountType));
             }
-            accounts.add(account);
+        } finally {
+            c.close();
         }
-        c.deactivate();
 
         // Clear the auth tokens for all these accounts so that we are sure
         // they will still be valid until the next time we refresh them.
-        // TODO: add this when the google login service is done
+        // TODO(fredq): add this when the google login service is done
 
         // mark the feeds dirty, by setting the accounts to the same value,
         //  which will trigger a sync.
         try {
             ContentValues values = new ContentValues();
-            for (String account : accounts) {
-                values.put(SyncConstValue._SYNC_ACCOUNT, account);
+            for (Account account : accounts) {
+                values.put(SyncConstValue._SYNC_ACCOUNT, account.mName);
+                values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.mType);
                 contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
-                        SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+                        SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND "
+                                + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
+                        new String[] {account.mName, account.mType});
             }
         } catch (SQLiteFullException e) {
             Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
index 9ecc3d6..d87f5e7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -39,7 +39,7 @@
 public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
     private static final String TAG = "SubscribedFeedsProvider";
     private static final String DATABASE_NAME = "subscribedfeeds.db";
-    private static final int DATABASE_VERSION = 10;
+    private static final int DATABASE_VERSION = 11;
 
     private static final int FEEDS = 1;
     private static final int FEED_ID = 2;
@@ -88,6 +88,7 @@
         db.execSQL("CREATE TABLE feeds (" +
                     "_id INTEGER PRIMARY KEY," +
                     "_sync_account TEXT," + // From the sync source
+                    "_sync_account_type TEXT," + // From the sync source
                     "_sync_id TEXT," + // From the sync source
                     "_sync_time TEXT," + // From the sync source
                     "_sync_version TEXT," + // From the sync source
@@ -106,8 +107,8 @@
                     "WHEN old._sync_id is not null " +
                     "BEGIN " +
                         "INSERT INTO _deleted_feeds " +
-                            "(_sync_id, _sync_account, _sync_version) " +
-                            "VALUES (old._sync_id, old._sync_account, " +
+                            "(_sync_id, _sync_account, _sync_account_type, _sync_version) " +
+                            "VALUES (old._sync_id, old._sync_account, old._sync_account_type, " +
                             "old._sync_version);" +
                     "END");
 
@@ -116,6 +117,7 @@
                     "_sync_id TEXT," +
                     (isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
                     "_sync_account TEXT," +
+                    "_sync_account_type TEXT," +
                     "_sync_mark INTEGER, " + // Used to filter out new rows
                     "UNIQUE(_sync_id))");
     }
@@ -170,7 +172,8 @@
                 qb.setDistinct(true);
                 qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
                 return qb.query(getDatabase(), projection, selection, selectionArgs,
-                        SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
+                        SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + ","
+                                + SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
             case FEED_ID:
                 qb.setTables(sFeedsTable);
                 qb.appendWhere(sFeedsTable + "._id=");
@@ -310,6 +313,8 @@
             DatabaseUtils.cursorStringToContentValues(diffsCursor,
                     SubscribedFeeds.Feeds._SYNC_ACCOUNT, mValues);
             DatabaseUtils.cursorStringToContentValues(diffsCursor,
+                    SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, mValues);
+            DatabaseUtils.cursorStringToContentValues(diffsCursor,
                     SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
             db.replace(mDeletedTable, SubscribedFeeds.Feeds._SYNC_ID, mValues);
         }
@@ -369,5 +374,7 @@
         ACCOUNTS_PROJECTION_MAP = map;
         map.put(SubscribedFeeds.Accounts._COUNT, "COUNT(*) AS _count");
         map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT, SubscribedFeeds.Accounts._SYNC_ACCOUNT);
+        map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE,
+                SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE);
     }
 }
diff --git a/preloaded-classes b/preloaded-classes
index 7d719e9..d1360eb 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,7 +1,5 @@
 # Classes which are preloaded by com.android.internal.os.ZygoteInit.
 android.R$styleable
-android.accounts.AccountMonitor
-android.accounts.AccountMonitor$AccountUpdater
 android.app.Activity
 android.app.ActivityGroup
 android.app.ActivityManager$MemoryInfo$1
@@ -213,7 +211,6 @@
 android.media.AudioManager
 android.media.IAudioService$Stub
 android.media.IAudioService$Stub$Proxy
-android.media.MediaPlayer
 android.net.LocalSocket
 android.net.LocalSocketAddress
 android.net.LocalSocketAddress$Namespace
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1f508a6..efca2cb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,12 +32,7 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.media.AudioService;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
+import android.os.*;
 import android.provider.Contacts.People;
 import android.provider.Settings;
 import android.server.BluetoothA2dpService;
@@ -45,6 +40,7 @@
 import android.server.search.SearchManagerService;
 import android.util.EventLog;
 import android.util.Log;
+import android.accounts.AccountManagerService;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -117,6 +113,14 @@
 
             mContentResolver = context.getContentResolver();
 
+            try {
+                Log.i(TAG, "Starting Account Manager.");
+                ServiceManager.addService(Context.ACCOUNT_SERVICE,
+                        new AccountManagerService(context));
+            } catch (Throwable e) {
+                Log.e(TAG, "Failure starting Account Manager", e);
+            }
+
             Log.i(TAG, "Starting Content Manager.");
             ContentService.main(context,
                     factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 2866666..03d95b7 100644
--- a/test-runner/android/test/IsolatedContext.java
+++ b/test-runner/android/test/IsolatedContext.java
@@ -2,6 +2,8 @@
 
 import com.google.android.collect.Lists;
 
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
 import android.content.ContextWrapper;
 import android.content.ContentResolver;
 import android.content.Intent;
@@ -11,6 +13,8 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
 
 import java.util.List;
 
@@ -21,6 +25,7 @@
 public class IsolatedContext extends ContextWrapper {
 
     private ContentResolver mResolver;
+    private final MockAccountManager mMockAccountManager;
 
     private List<Intent> mBroadcastIntents = Lists.newArrayList();
 
@@ -28,6 +33,7 @@
             ContentResolver resolver, Context targetContext) {
         super(targetContext);
         mResolver = resolver;
+        mMockAccountManager = new MockAccountManager();
     }
 
     /** Returns the list of intents that were broadcast since the last call to this method. */
@@ -78,8 +84,21 @@
 
     @Override
     public Object getSystemService(String name) {
-        // No services exist in this context.
+        if (Context.ACCOUNT_SERVICE.equals(name)) {
+            return mMockAccountManager;
+        }
+        // No other services exist in this context.
         return null;
     }
 
+    private class MockAccountManager extends AccountManager {
+        public MockAccountManager() {
+            super(IsolatedContext.this, null /* IAccountManager */, null /* handler */);
+        }
+
+        public void addOnAccountsUpdatedListener(OnAccountsUpdatedListener listener,
+                Handler handler, boolean updateImmediately) {
+            // do nothing
+        }
+    }
 }
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index c1d2507..0b4bfed 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -23,6 +23,8 @@
 import android.os.SystemClock;
 import android.provider.Sync;
 import android.net.Uri;
+import android.accounts.Account;
+
 import java.util.Map;
 
 /**
@@ -49,7 +51,8 @@
     protected void syncProvider(Uri uri, String account, String authority) throws Exception {
         Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
-        extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+        Account account1 = new Account(account, "com.google.GAIA");
+        extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT, account1);
 
         mContentResolver.startSync(uri, extras);
         long startTimeInMillis = SystemClock.elapsedRealtime();
@@ -66,7 +69,7 @@
                 break;
             }
 
-            if (isSyncActive(account, authority)) {
+            if (isSyncActive(account1, authority)) {
                 counter = 0;
                 continue;
             }
@@ -87,7 +90,7 @@
      * entry is in either the Pending or Active tables.
      * @return
      */
-    private boolean isSyncActive(String account, String authority) {
+    private boolean isSyncActive(Account account, String authority) {
         Sync.Pending.QueryMap pendingQueryMap = null;
         Sync.Active.QueryMap activeQueryMap = null;
         try {
@@ -107,11 +110,12 @@
         }
     }
 
-    private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, String account,
+    private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, Account account,
                                              String authority) {
         Map<String, ContentValues> rows = activemap.getRows();
         for (ContentValues values : rows.values()) {
-            if (values.getAsString("account").equals(account)
+            if (values.getAsString("account").equals(account.mName)
+                    && values.getAsString("account_type").equals(account.mType)
                     && values.getAsString("authority").equals(authority)) {
                 return true;
             }
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
index 0cdf63f..6c3710a 100755
--- a/tests/AndroidTests/run_test.sh
+++ b/tests/AndroidTests/run_test.sh
@@ -1,4 +1,4 @@
 framework=/system/framework
 bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
-adb shell exec dalvikvm  -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \
+adb shell exec dalvikvm  -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk:data/app/AndroidTests.apk \
       com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
new file mode 100644
index 0000000..6b8e1f0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
@@ -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.
+ */
+
+package com.android.unit_tests.accounts;
+
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.IsolatedContext;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.content.*;
+import android.accounts.Account;
+import android.accounts.AccountManagerService;
+import android.os.Bundle;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+
+public class AccountManagerServiceTest extends AndroidTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        final String filenamePrefix = "test.";
+        MockContentResolver resolver = new MockContentResolver();
+        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+                new MockContext(), // The context that most methods are delegated to
+                getContext(), // The context that file methods are delegated to
+                filenamePrefix);
+        Context context = new IsolatedContext(resolver, targetContextWrapper);
+        setContext(context);
+    }
+
+    public class AccountSorter implements Comparator<Account> {
+        public int compare(Account object1, Account object2) {
+            if (object1 == object2) return 0;
+            if (object1 == null) return 1;
+            if (object2 == null) return -1;
+            int result = object1.mType.compareTo(object2.mType);
+            if (result != 0) return result;
+            return object1.mName.compareTo(object2.mName);
+        }
+    }
+
+    public void testCheckAddAccount() throws Exception {
+        AccountManagerService ams = new AccountManagerService(getContext());
+        Account a11 = new Account("account1", "type1");
+        Account a21 = new Account("account2", "type1");
+        Account a31 = new Account("account3", "type1");
+        Account a12 = new Account("account1", "type2");
+        Account a22 = new Account("account2", "type2");
+        Account a32 = new Account("account3", "type2");
+        assertTrue(ams.addAccount(a11, "p11", null));
+        assertTrue(ams.addAccount(a12, "p12", null));
+        assertTrue(ams.addAccount(a21, "p21", null));
+        assertTrue(ams.addAccount(a22, "p22", null));
+        assertTrue(ams.addAccount(a31, "p31", null));
+        assertTrue(ams.addAccount(a32, "p32", null));
+
+        assertFalse("duplicate account insertion should fail", ams.addAccount(a32, "p", null));
+
+        Account[] accounts = ams.getAccounts();
+        Arrays.sort(accounts, new AccountSorter());
+        assertEquals(6, accounts.length);
+        assertEquals(a11, accounts[0]);
+        assertEquals(a21, accounts[1]);
+        assertEquals(a31, accounts[2]);
+        assertEquals(a12, accounts[3]);
+        assertEquals(a22, accounts[4]);
+        assertEquals(a32, accounts[5]);
+
+        accounts = ams.getAccountsByType("type1" );
+        Arrays.sort(accounts, new AccountSorter());
+        assertEquals(3, accounts.length);
+        assertEquals(a11, accounts[0]);
+        assertEquals(a21, accounts[1]);
+        assertEquals(a31, accounts[2]);
+
+        ams.removeAccount(a21);
+
+        accounts = ams.getAccountsByType("type1" );
+        Arrays.sort(accounts, new AccountSorter());
+        assertEquals(2, accounts.length);
+        assertEquals(a11, accounts[0]);
+        assertEquals(a31, accounts[1]);
+    }
+
+    public void testPasswords() throws Exception {
+        AccountManagerService ams = new AccountManagerService(getContext());
+        Account a11 = new Account("account1", "type1");
+        Account a12 = new Account("account1", "type2");
+        assertTrue(ams.addAccount(a11, "p11", null));
+        assertTrue(ams.addAccount(a12, "p12", null));
+
+        assertEquals("p11", ams.getPassword(a11));
+        assertEquals("p12", ams.getPassword(a12));
+
+        ams.setPassword(a11, "p11b");
+
+        assertEquals("p11b", ams.getPassword(a11));
+        assertEquals("p12", ams.getPassword(a12));
+    }
+
+    public void testUserdata() throws Exception {
+        AccountManagerService ams = new AccountManagerService(getContext());
+        Account a11 = new Account("account1", "type1");
+        Bundle u11 = new Bundle();
+        u11.putString("a", "a_a11");
+        u11.putString("b", "b_a11");
+        u11.putString("c", "c_a11");
+        Account a12 = new Account("account1", "type2");
+        Bundle u12 = new Bundle();
+        u12.putString("a", "a_a12");
+        u12.putString("b", "b_a12");
+        u12.putString("c", "c_a12");
+        assertTrue(ams.addAccount(a11, "p11", u11));
+        assertTrue(ams.addAccount(a12, "p12", u12));
+
+        assertEquals("a_a11", ams.getUserData(a11, "a"));
+        assertEquals("b_a11", ams.getUserData(a11, "b"));
+        assertEquals("c_a11", ams.getUserData(a11, "c"));
+        assertEquals("a_a12", ams.getUserData(a12, "a"));
+        assertEquals("b_a12", ams.getUserData(a12, "b"));
+        assertEquals("c_a12", ams.getUserData(a12, "c"));
+
+        ams.setUserData(a11, "b", "b_a11b");
+
+        assertEquals("a_a11", ams.getUserData(a11, "a"));
+        assertEquals("b_a11b", ams.getUserData(a11, "b"));
+        assertEquals("c_a11", ams.getUserData(a11, "c"));
+        assertEquals("a_a12", ams.getUserData(a12, "a"));
+        assertEquals("b_a12", ams.getUserData(a12, "b"));
+        assertEquals("c_a12", ams.getUserData(a12, "c"));
+    }
+
+    public void testAuthtokens() throws Exception {
+        AccountManagerService ams = new AccountManagerService(getContext());
+        Account a11 = new Account("account1", "type1");
+        Account a12 = new Account("account1", "type2");
+        assertTrue(ams.addAccount(a11, "p11", null));
+        assertTrue(ams.addAccount(a12, "p12", null));
+
+        ams.setAuthToken(a11, "att1", "a11_att1");
+        ams.setAuthToken(a11, "att2", "a11_att2");
+        ams.setAuthToken(a11, "att3", "a11_att3");
+        ams.setAuthToken(a12, "att1", "a12_att1");
+        ams.setAuthToken(a12, "att2", "a12_att2");
+        ams.setAuthToken(a12, "att3", "a12_att3");
+
+        assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+        assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+        assertEquals("a11_att3", ams.peekAuthToken(a11, "att3"));
+        assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+        assertEquals("a12_att2", ams.peekAuthToken(a12, "att2"));
+        assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+        ams.setAuthToken(a11, "att3", "a11_att3b");
+        ams.invalidateAuthToken(a12.mType, "a12_att2");
+
+        assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+        assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+        assertEquals("a11_att3b", ams.peekAuthToken(a11, "att3"));
+        assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+        assertNull(ams.peekAuthToken(a12, "att2"));
+        assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+        assertNull(ams.readAuthTokenFromDatabase(a12, "att2"));
+    }
+}
\ No newline at end of file
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
index 36805b1..27f1b8b 100644
--- a/tests/CoreTests/android/content/SyncStorageEngineTest.java
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -21,6 +21,7 @@
 import android.test.mock.MockContext;
 import android.test.mock.MockContentResolver;
 import android.provider.Sync;
+import android.accounts.Account;
 
 public class SyncStorageEngineTest extends AndroidTestCase {
 
@@ -29,7 +30,7 @@
      * correcponding sync is finished. This can happen if the clock changes while we are syncing.
      */
     public void testPurgeActiveSync() throws Exception {
-        final String account = "a@example.com";
+        final Account account = new Account("a@example.com", "example.type");
         final String authority = "testprovider";
 
         MockContentResolver mockResolver = new MockContentResolver();
diff --git a/tests/DumpRenderTree/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py
similarity index 92%
rename from tests/DumpRenderTree/run_page_cycler.py
rename to tests/DumpRenderTree/assets/run_page_cycler.py
index 9a099b5..2325047 100755
--- a/tests/DumpRenderTree/run_page_cycler.py
+++ b/tests/DumpRenderTree/assets/run_page_cycler.py
@@ -56,10 +56,11 @@
   run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
 
   # Call LoadTestsAutoTest::runTest.
-  run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
+  run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
 
   (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-  if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+  if adb_output.find('INSTRUMENTATION_FAILED') != -1 or \
+      adb_output.find('Process crashed.') != -1:
     logging.error("Error happened : " + adb_output)
     sys.exit(1)
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 39eae02..562b1f3 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,24 +16,11 @@
 
 package com.android.dumprendertree;
 
-import android.app.Activity;
 import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Intent;
-
-import android.util.Log;
-import android.view.KeyEvent;
-import android.webkit.WebSettings;
-
 import android.os.Bundle;
-import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.dumprendertree.TestShellActivity;
+import android.util.Log;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
@@ -141,6 +128,7 @@
     private Vector<String> mTestList;
     private boolean mRebaselineResults;
     private String mTestPathPrefix;
+    private boolean mFinished;
     
     public LayoutTestsAutoTest() {
       super("com.android.dumprendertree", TestShellActivity.class);
@@ -290,6 +278,7 @@
         activity.setCallback(new TestShellCallback() {
             public void finished() {
                 synchronized (LayoutTestsAutoTest.this) {
+                    mFinished = true;
                     LayoutTestsAutoTest.this.notifyAll();
                 }
             }         
@@ -306,6 +295,7 @@
             resultFile = getAndroidExpectedResultFile(expectedResultFile);
         }
         
+        mFinished = false;
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(activity, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
@@ -316,9 +306,11 @@
       
         // Wait until done.
         synchronized (this) {
-            try {
-                this.wait();
-            } catch (InterruptedException e) { }
+            while(!mFinished){
+                try {
+                    this.wait();
+                } catch (InterruptedException e) { }
+            }
         }
         
         if (!mRebaselineResults) {
@@ -478,7 +470,7 @@
                 byte[] buf = new byte[2048];
                 int len;
 
-                while ((len = in.read(buf)) > 0 ) {
+                while ((len = in.read(buf)) >= 0 ) {
                     out.write(buf, 0, len);
                 }
                 out.close();
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index b064dbb..5cb5155 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -16,52 +16,34 @@
 
 package com.android.dumprendertree;
 
-import android.app.Activity;
 import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
 import android.content.Intent;
 
 import android.util.Log;
 
 import android.os.Bundle;
+import android.os.Debug;
+import android.os.Debug.MemoryInfo;
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.dumprendertree.TestShellActivity;
 import com.android.dumprendertree.TestShellCallback;
 
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-
-class StreamPipe extends Thread {
-    InputStream in;
-    OutputStream out;
-    
-    StreamPipe(InputStream in, OutputStream out) {
-        this.in = in;
-        this.out = out;
-    }
-    
-    public void run() {
-        try {
-            byte[] buf = new byte[1024];
-            int nofb = this.in.read(buf);
-            while (nofb != -1) {
-                this.out.write(buf, 0, nofb);
-                nofb = this.in.read(buf);
-            }          
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-}
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
 
 public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
 
     private final static String LOGTAG = "LoadTest";
     private final static String LOAD_TEST_RESULT = "/sdcard/load_test_result.txt";
-    
+    private boolean mFinished;
+    static final String LOAD_TEST_RUNNER_FILES[] = {
+        "run_page_cycler.py"
+  };
+
     public LoadTestsAutoTest() {
         super("com.android.dumprendertree", TestShellActivity.class);
     }
@@ -74,17 +56,17 @@
         bundle.putBoolean(file, result);
         inst.sendStatus(0, bundle);
     }
-    
+
     // Invokes running of layout tests
     // and waits till it has finished running.
-    public void runTest() {
+    public void runPageCyclerTest() {
         LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
 
         if (runner.mTestPath == null) {
             Log.e(LOGTAG, "No test specified");
             return;
         }
-        
+
         TestShellActivity activity = (TestShellActivity) getActivity();
 
         // Run tests
@@ -92,48 +74,69 @@
 
         // TODO(fqian): let am instrumentation pass in the command line, currently
         // am instrument does not allow spaces in the command.
-        runPostShellCommand("/system/bin/dumpsys meminfo");
-        
+        dumpMemoryInfo();
+
         // Kill activity
         activity.finish();
     }
 
-    private void runPostShellCommand(String cmd) {
-        if (cmd == null || cmd.length() == 0)
-            return;
-        
+    private void dumpMemoryInfo() {
         try {
-            // Call dumpsys meminfo
-            Process proc = Runtime.getRuntime().exec(cmd);
-            // Append output to LOAD_TEST_RESULT
-            InputStream input = proc.getInputStream();
-            InputStream error = proc.getErrorStream();
-            FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true);
+            Log.v(LOGTAG, "Dumping memory information.");
 
-            StreamPipe p_in = new StreamPipe(input, out);
-            StreamPipe p_err = new StreamPipe(error, System.err);
-            
-            p_in.start();
-            p_err.start();
-            
-            proc.waitFor();
+            FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true);
+            PrintStream ps = new PrintStream(out);
+
+            MemoryInfo mi = new MemoryInfo();
+            Debug.getMemoryInfo(mi);
+
+            //try to fake the dumpsys format
+            //this will eventually be changed to XML
+            String format = "%15s:%9d%9d%9d%9d";
+            String pss =
+              String.format(format, "(Pss)",
+                  mi.nativePss, mi.dalvikPss, mi.otherPss,
+                  mi.nativePss + mi.dalvikPss + mi.otherPss);
+            String sd =
+              String.format(format, "(shared dirty)",
+                  mi.nativeSharedDirty, mi.dalvikSharedDirty, mi.otherSharedDirty,
+                  mi.nativeSharedDirty + mi.dalvikSharedDirty + mi.otherSharedDirty);
+            String pd =
+              String.format(format, "(priv dirty)",
+                  mi.nativePrivateDirty, mi.dalvikPrivateDirty, mi.otherPrivateDirty,
+                  mi.nativePrivateDirty + mi.dalvikPrivateDirty + mi.otherPrivateDirty);
+
+            ps.print("\n\n\n");
+            ps.println("** MEMINFO in pid 0 [com.android.dumprendertree] **");
+            ps.println("                   native   dalvik    other    total");
+            ps.println("           size:    12060     5255      N/A    17315");
+            ps.println("      allocated:    12060     5255      N/A    17315");
+            ps.println("           free:    12060     5255      N/A    17315");
+            ps.println(pss);
+            ps.println(sd);
+            ps.println(pd);
+            ps.print("\n\n\n");
+            ps.flush();
+            ps.close();
+            out.flush();
+            out.close();
         } catch (IOException e) {
             Log.e(LOGTAG, e.getMessage());
-        } catch (InterruptedException e) {
-            Log.e(LOGTAG, e.getMessage());
-        }      
+        }
     }
-    
+
     // A convenient method to be called by another activity.
     private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
         activity.setCallback(new TestShellCallback() {
             public void finished() {
                 synchronized (LoadTestsAutoTest.this) {
+                    mFinished = true;
                     LoadTestsAutoTest.this.notifyAll();
                 }
-            }         
+            }
         });
-        
+
+        mFinished = false;
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(activity, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
@@ -141,12 +144,41 @@
         intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
         intent.putExtra(TestShellActivity.RESULT_FILE, LOAD_TEST_RESULT);
         activity.startActivity(intent);
-        
+
         // Wait until done.
         synchronized (this) {
-            try {
-                this.wait();
-            } catch (InterruptedException e) { }
+            while(!mFinished) {
+                try {
+                    this.wait();
+                } catch (InterruptedException e) { }
+            }
         }
-    }   
+    }
+
+    public void copyRunnerAssetsToCache() {
+        try {
+            String out_dir = getActivity().getApplicationContext()
+                .getCacheDir().getPath() + "/";
+
+            for( int i=0; i< LOAD_TEST_RUNNER_FILES.length; i++) {
+                InputStream in = getActivity().getAssets().open(
+                        LOAD_TEST_RUNNER_FILES[i]);
+                OutputStream out = new FileOutputStream(
+                        out_dir + LOAD_TEST_RUNNER_FILES[i]);
+
+                byte[] buf = new byte[2048];
+                int len;
+
+                while ((len = in.read(buf)) >= 0 ) {
+                    out.write(buf, 0, len);
+                }
+                out.close();
+                in.close();
+            }
+        }catch (IOException e) {
+          e.printStackTrace();
+        }
+
+    }
+
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index bf8a3b3..404d101 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -165,7 +165,8 @@
             if (mDialogStrings != null)
                 os.write(mDialogStrings.toString().getBytes());
             mDialogStrings = null;
-            os.write(webkitData.getBytes());
+            if (webkitData != null)
+                os.write(webkitData.getBytes());
             os.flush();
             os.close();
         } catch (IOException ex) {
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index aa3d186..42c1e78 100644
--- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -8,6 +8,7 @@
 import android.net.Uri;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
+import android.accounts.Account;
 
 import java.util.ArrayList;
 import java.util.Map;
@@ -26,7 +27,7 @@
     static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
     static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
 
-    private final String ACCOUNT = "account@goo.com";
+    private final Account ACCOUNT = new Account("account@goo.com", "example.type");
 
     private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
 
@@ -65,25 +66,31 @@
         mExpectations.clear();
     }
 
-    ContentValues newValues(String data, String syncId, String syncAccount,
+    ContentValues newValues(String data, String syncId, Account syncAccount,
             String syncTime, String syncVersion, Long syncLocalId) {
         ContentValues values = new ContentValues();
         if (data != null) values.put("data", data);
         if (syncTime != null) values.put("_sync_time", syncTime);
         if (syncVersion != null) values.put("_sync_version", syncVersion);
         if (syncId != null) values.put("_sync_id", syncId);
-        if (syncAccount != null) values.put("_sync_account", syncAccount);
+        if (syncAccount != null) {
+            values.put("_sync_account", syncAccount.mName);
+            values.put("_sync_account_type", syncAccount.mType);
+        }
         values.put("_sync_local_id", syncLocalId);
         values.put("_sync_dirty", 0);
         return values;
     }
 
-    ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+    ContentValues newDeletedValues(String syncId, Account syncAccount, String syncVersion,
             Long syncLocalId) {
         ContentValues values = new ContentValues();
         if (syncVersion != null) values.put("_sync_version", syncVersion);
         if (syncId != null) values.put("_sync_id", syncId);
-        if (syncAccount != null) values.put("_sync_account", syncAccount);
+        if (syncAccount != null) {
+            values.put("_sync_account", syncAccount.mName);
+            values.put("_sync_account_type", syncAccount.mType);
+        }
         if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
         return values;
     }
@@ -380,6 +387,7 @@
                     + "_sync_local_id INTEGER, "
                     + "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
                     + "_sync_account TEXT, "
+                    + "_sync_account_type TEXT, "
                     + "_sync_mark INTEGER)");
 
             mDb.execSQL("CREATE TABLE deleted_items ("
@@ -388,6 +396,7 @@
                     + "_sync_id TEXT, "
                     + "_sync_local_id INTEGER, "
                     + "_sync_account TEXT, "
+                    + "_sync_account_type TEXT, "
                     + "_sync_mark INTEGER)");
         }
 
@@ -501,7 +510,7 @@
             throw new UnsupportedOperationException();
         }
 
-        public void onSyncStart(SyncContext context, String account) {
+        public void onSyncStart(SyncContext context, Account account) {
             throw new UnsupportedOperationException();
         }
 
@@ -509,7 +518,7 @@
             throw new UnsupportedOperationException();
         }
 
-        public String getSyncingAccount() {
+        public Account getSyncingAccount() {
             throw new UnsupportedOperationException();
         }
 
@@ -544,24 +553,24 @@
             throw new UnsupportedOperationException();
         }
 
-        protected void onAccountsChanged(String[] accountsArray) {
+        protected void onAccountsChanged(Account[] accountsArray) {
             throw new UnsupportedOperationException();
         }
 
-        protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
-                String accountColumnName) {
+        protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table
+        ) {
             throw new UnsupportedOperationException();
         }
 
-        public void wipeAccount(String account) {
+        public void wipeAccount(Account account) {
             throw new UnsupportedOperationException();
         }
 
-        public byte[] readSyncDataBytes(String account) {
+        public byte[] readSyncDataBytes(Account account) {
             throw new UnsupportedOperationException();
         }
 
-        public void writeSyncDataBytes(String account, byte[] data) {
+        public void writeSyncDataBytes(Account account, byte[] data) {
             throw new UnsupportedOperationException();
         }
     }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 01c8140..2ef0347 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -125,7 +125,9 @@
         {
             //printf("new AaptFile created %s\n", (const char*)sourceFile);
         }
-    virtual ~AaptFile() { }
+    virtual ~AaptFile() {
+        free(mData);
+    }
 
     const String8& getPath() const { return mPath; }
     const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
@@ -441,7 +443,13 @@
     AaptSymbolEntry                                 mDefSymbol;
 };
 
-class ResourceTypeSet;
+class ResourceTypeSet : public RefBase,
+                        public KeyedVector<String8,sp<AaptGroup> >
+{
+public:
+    ResourceTypeSet();
+};
+
 
 /**
  * Asset hierarchy being operated on.
@@ -449,8 +457,8 @@
 class AaptAssets : public AaptDir
 {
 public:
-    AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false) { }
-    virtual ~AaptAssets() { }
+    AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false), mRes(NULL) { }
+    virtual ~AaptAssets() { delete mRes; }
 
     const String8& getPackage() const { return mPackage; }
     void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; }
@@ -498,7 +506,7 @@
     
     inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
     inline void 
-        setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { mRes = res; }
+        setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
 
 private:
     String8 mPackage;
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 0a4c68b..f2414dd 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -44,6 +44,9 @@
             }
             free(allocRows);
         }
+        free(info9Patch.xDivs);
+        free(info9Patch.yDivs);
+        free(info9Patch.colors);
     }
 
     png_uint_32 width;
@@ -833,6 +836,7 @@
     int i;
 
     png_unknown_chunk unknowns[1];
+    unknowns[0].data = NULL;
 
     png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * png_sizeof(png_bytep));
     if (outRows == (png_bytepp) 0) {
@@ -939,6 +943,7 @@
         free(outRows[i]);
     }
     free(outRows);
+    free(unknowns[0].data);
 
     png_get_IHDR(write_ptr, write_info, &width, &height,
        &bit_depth, &color_type, &interlace_type,
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index b2bd9ff..2e4d0a4 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -45,13 +45,6 @@
     }
 }
 
-class ResourceTypeSet : public RefBase,
-                        public KeyedVector<String8,sp<AaptGroup> >
-{
-public:
-    ResourceTypeSet();
-};
-
 ResourceTypeSet::ResourceTypeSet()
     :RefBase(),
      KeyedVector<String8,sp<AaptGroup> >()
@@ -1055,6 +1048,7 @@
                 printf("  Writing public definitions to %s.\n", bundle->getPublicOutputFile());
             }
             table.writePublicDefinitions(String16(assets->getPackage()), fp);
+            fclose(fp);
         }
 
         NOISY(
@@ -1072,7 +1066,6 @@
             return err;
         }
     }
-
     return err;
 }
 
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index d476567..50a2185 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -486,6 +486,7 @@
 XMLNode::XMLNode(const String8& filename)
     : mFilename(filename)
 {
+    memset(&mCharsValue, 0, sizeof(mCharsValue));
 }
 
 XMLNode::type XMLNode::getType() const
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 91802a9..1856cb9 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -841,23 +841,6 @@
         fprintf(to, "package %s;\n", this->package.c_str());
     }
 
-    // gather the types for the import statements
-    set<Type*> types;
-    N = this->classes.size();
-    for (i=0; i<N; i++) {
-        Class* c = this->classes[i];
-        c->GatherTypes(&types);
-    }
-    
-    set<Type*>::iterator it;
-    for (it=types.begin(); it!=types.end(); it++) {
-        Type* t = *it;
-        string pkg = t->Package();
-        if (pkg.length() != 0 && pkg != this->package) {
-            fprintf(to, "import %s;\n", t->ImportType().c_str());
-        }
-    }
-
     N = this->classes.size();
     for (i=0; i<N; i++) {
         Class* c = this->classes[i];
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 1dedd04..aec2164 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -5,6 +5,7 @@
 #include <vector>
 #include <set>
 #include <stdarg.h>
+#include <stdio.h>
 
 using namespace std;
 
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index e3c0af0..da20d1f 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,6 +1,7 @@
 #include "generate_java.h"
 #include "AST.h"
 #include "Type.h"
+#include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -133,7 +134,7 @@
 
     Method* m = new Method;
         m->comment = "/**\n * Cast an IBinder object into an ";
-        m->comment += interfaceType->Name();
+        m->comment += interfaceType->QualifiedName();
         m->comment += " interface,\n";
         m->comment += " * generating a proxy if needed.\n */";
         m->modifiers = PUBLIC | STATIC;
@@ -323,7 +324,7 @@
     transactCodeName += method->name.data;
 
     char transactCodeValue[50];
-    sprintf(transactCodeValue, "(IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
 
     Field* transactCode = new Field(STATIC | FINAL,
                             new Variable(INT_TYPE, transactCodeName));
@@ -517,7 +518,7 @@
                             new LiteralExpression("Stub." + transactCodeName),
                             _data, _reply ? _reply : NULL_VALUE,
                             new LiteralExpression(
-                                oneway ? "IBinder.FLAG_ONEWAY" : "0"));
+                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
     tryStatement->statements->Add(call);
 
     // throw back exceptions.
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index e9bf0f7..d88d988 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,6 +1,7 @@
 #ifndef DEVICE_TOOLS_AIDL_H
 #define DEVICE_TOOLS_AIDL_H
 
+#include <string.h>
 #include <string>
 #include <vector>
 
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 3425668..a7f301e 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -5,7 +5,10 @@
 #include <sstream>
 #include <sys/types.h>
 #include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/wait.h>
+#include <cstdio>
 
 using namespace std;
 
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 9d7c5c6..dd54f3a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -2,6 +2,7 @@
 
 #include <stdarg.h>
 #include <set>
+#include <cstdio>
 
 using namespace std;
 
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
index e396f8b..8623b97 100644
--- a/tools/localize/Values.cpp
+++ b/tools/localize/Values.cpp
@@ -1,5 +1,6 @@
 #include "Values.h"
 #include <stdlib.h>
+#include <cstdio>
 
 
 // =====================================================================================
diff --git a/tools/localize/XLIFFFile.cpp b/tools/localize/XLIFFFile.cpp
index 51f81de..4e217d9 100644
--- a/tools/localize/XLIFFFile.cpp
+++ b/tools/localize/XLIFFFile.cpp
@@ -3,6 +3,7 @@
 #include <algorithm>
 #include <sys/time.h>
 #include <time.h>
+#include <cstdio>
 
 const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
 
diff --git a/tools/localize/XMLHandler.h b/tools/localize/XMLHandler.h
index 1130710..324385f 100644
--- a/tools/localize/XMLHandler.h
+++ b/tools/localize/XMLHandler.h
@@ -3,6 +3,7 @@
 
 #include "SourcePos.h"
 
+#include <algorithm>
 #include <string>
 #include <vector>
 #include <map>
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index bb82a9c..c0981d8 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -6,6 +6,9 @@
 #include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <cstdio>
 #include <host/Directories.h>
 #include "log.h"
 
diff --git a/tools/localize/file_utils.h b/tools/localize/file_utils.h
index 3b3fa21..7706587 100644
--- a/tools/localize/file_utils.h
+++ b/tools/localize/file_utils.h
@@ -4,6 +4,7 @@
 #include "ValuesFile.h"
 #include "Configuration.h"
 #include <string>
+#include <cstdio>
 
 using namespace std;
 
diff --git a/tools/localize/localize.cpp b/tools/localize/localize.cpp
index c0d84cc..68c03b6 100644
--- a/tools/localize/localize.cpp
+++ b/tools/localize/localize.cpp
@@ -15,6 +15,7 @@
 #include <sstream>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 
 using namespace std;
 
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 63d904c..931ea95 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
 #include "XLIFFFile.h"
 #include "ValuesFile.h"
 #include "localize.h"
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index 5a2b0f4..f638a74 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
 #include "merge_res_and_xliff.h"