Merge "Add PROPERTY_IMS_REG_REQUIRED." into ics-factoryrom
diff --git a/api/14.txt b/api/14.txt
index 0aa94b2..45bb882 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -2072,7 +2072,7 @@
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
-    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], android.os.Bundle);
+    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
diff --git a/api/current.txt b/api/current.txt
index 0aa94b2..45bb882 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2072,7 +2072,7 @@
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
-    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], android.os.Bundle);
+    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 530ecf1..150880c 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1782,7 +1782,8 @@
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
-     * <pre>  newChooseAccountsIntent(null, null, new String[]{"com.google"}, null);</pre>
+     * <pre>  newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null,
+     * null, null, null);</pre>
      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
      * selected one, according to the caller's definition of selected.
      * @param allowableAccounts an optional {@link ArrayList} of accounts that are allowed to be
@@ -1790,22 +1791,44 @@
      * @param allowableAccountTypes an optional string array of account types. These are used
      * both to filter the shown accounts and to filter the list of account types that are shown
      * when adding an account.
-     * @param addAccountOptions This {@link Bundle} is passed as the addAccount options
-     * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. 
+     * @param alwaysPromptForAccount if set the account chooser screen is always shown, otherwise
+     * it is only shown when there is more than one account from which to choose
+     * @param descriptionOverrideText if non-null this string is used as the description in the
+     * accounts chooser screen rather than the default
+     * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
+     * authTokenType parameter
+     * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
+     * requiredFeatures parameter
+     * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
+     * parameter
+     * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
      */
     static public Intent newChooseAccountIntent(Account selectedAccount,
             ArrayList<Account> allowableAccounts,
             String[] allowableAccountTypes,
+            boolean alwaysPromptForAccount,
+            String descriptionOverrideText,
+            String addAccountAuthTokenType,
+            String[] addAccountRequiredFeatures,
             Bundle addAccountOptions) {
         Intent intent = new Intent();
         intent.setClassName("android", "android.accounts.ChooseTypeAndAccountActivity");
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
                 allowableAccounts);
-        intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST,
-                allowableAccountTypes != null ? Lists.newArrayList(allowableAccountTypes) : 0);
+        intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
+                allowableAccountTypes);
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
                 addAccountOptions);
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount);
+        intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT,
+                alwaysPromptForAccount);
+        intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE,
+                descriptionOverrideText);
+        intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
+                addAccountAuthTokenType);
+        intent.putExtra(
+                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
+                addAccountRequiredFeatures);
         return intent;
     }
 
diff --git a/core/java/android/accounts/ChooseAccountTypeActivity.java b/core/java/android/accounts/ChooseAccountTypeActivity.java
index 836164c..f53e6f3 100644
--- a/core/java/android/accounts/ChooseAccountTypeActivity.java
+++ b/core/java/android/accounts/ChooseAccountTypeActivity.java
@@ -52,12 +52,12 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.choose_account);
+        setContentView(R.layout.choose_account_type);
 
         // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
         Set<String> setOfAllowableAccountTypes = null;
         ArrayList<String> validAccountTypes = getIntent().getStringArrayListExtra(
-                ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST);
+                ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
         if (validAccountTypes != null) {
             setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.size());
             for (String type : validAccountTypes) {
@@ -138,10 +138,14 @@
 
     protected void runAddAccountForAuthenticator(AuthInfo authInfo) {
         Log.d(TAG, "selected account type " + authInfo.name);
-        Bundle options = getIntent().getBundleExtra(
+        final Bundle options = getIntent().getBundleExtra(
                 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);
-        AccountManager.get(this).addAccount(authInfo.desc.type, null, null, options,
-                this, this, null);
+        final String[] requiredFeatures = getIntent().getStringArrayExtra(
+                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);
+        final String authTokenType = getIntent().getStringExtra(
+                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);
+        AccountManager.get(this).addAccount(authInfo.desc.type, authTokenType, requiredFeatures,
+                options, this, this, null /* Handler */);
     }
 
     public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index a903399..b4030b9 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -23,6 +23,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -57,25 +58,68 @@
      * that match the types in this list, if this parameter is supplied. This list is also
      * used to filter the allowable account types if add account is selected.
      */
-    public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST = "allowableAccountTypes";
+    public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY = "allowableAccountTypes";
 
     /**
-     * This is passed as the options bundle in AccountManager.addAccount() if it is called.
+     * This is passed as the addAccountOptions parameter in AccountManager.addAccount()
+     * if it is called.
      */
     public static final String EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE = "addAccountOptions";
 
     /**
+     * This is passed as the requiredFeatures parameter in AccountManager.addAccount()
+     * if it is called.
+     */
+    public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY = 
+            "addAccountRequiredFeatures";
+
+    /**
+     * This is passed as the authTokenType string in AccountManager.addAccount()
+     * if it is called.
+     */
+    public static final String EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING = "authTokenType";
+
+    /**
      * If set then the specified account is already "selected".
      */
     public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
 
+    /**
+     * If true then display the account selection list even if there is just
+     * one account to choose from. boolean.
+     */
+    public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =
+            "alwaysPromptForAccount";
+
+    /**
+     * If set then this string willb e used as the description rather than
+     * the default.
+     */
+    public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
+            "descriptionTextOverride";
+
     private ArrayList<AccountInfo> mAccountInfos;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.choose_type_and_account);
+
+        // save some items we use frequently
         final AccountManager accountManager = AccountManager.get(this);
+        final Intent intent = getIntent();
+
+        // override the description text if supplied
+        final String descriptionOverride =
+                intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
+        if (!TextUtils.isEmpty(descriptionOverride)) {
+            ((TextView)findViewById(R.id.description)).setText(descriptionOverride);
+        }
+
+        // If the selected account matches one in the list we will place a
+        // checkmark next to it.
+        final Account selectedAccount =
+                (Account)intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
 
         // build an efficiently queryable map of account types to authenticator descriptions
         final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
@@ -87,7 +131,7 @@
         // Read the validAccounts, if present, and add them to the setOfAllowableAccounts
         Set<Account> setOfAllowableAccounts = null;
         final ArrayList<Parcelable> validAccounts =
-                getIntent().getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
+                intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
         if (validAccounts != null) {
             setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
             for (Parcelable parcelable : validAccounts) {
@@ -98,7 +142,7 @@
         // Read the validAccountTypes, if present, and add them to the setOfAllowableAccountTypes
         Set<String> setOfAllowableAccountTypes = null;
         final ArrayList<String> validAccountTypes =
-                getIntent().getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST);
+                intent.getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
         if (validAccountTypes != null) {
             setOfAllowableAccountTypes = new HashSet<String>(validAccountTypes.size());
             for (String type : validAccountTypes) {
@@ -121,7 +165,8 @@
                 continue;
             }
             mAccountInfos.add(new AccountInfo(account,
-                    getDrawableForType(typeToAuthDescription, account.type)));
+                    getDrawableForType(typeToAuthDescription, account.type),
+                    account.equals(selectedAccount)));
         }
 
         // If there are no allowable accounts go directly to add account
@@ -131,7 +176,8 @@
         }
 
         // if there is only one allowable account return it
-        if (mAccountInfos.size() == 1) {
+        if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
+                && mAccountInfos.size() == 1) {
             Account account = mAccountInfos.get(0).account;
             setResultAndFinish(account.name, account.type);
             return;
@@ -143,7 +189,6 @@
         list.setAdapter(new AccountArrayAdapter(this,
                 android.R.layout.simple_list_item_1, mAccountInfos));
         list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        list.setTextFilterEnabled(false);
         list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
             public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                 onListItemClick((ListView)parent, v, position, id);
@@ -173,10 +218,12 @@
                 return;
             }
         }
+        Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
         setResult(Activity.RESULT_CANCELED);
         finish();
     }
 
+
     private Drawable getDrawableForType(
             final HashMap<String, AuthenticatorDescription> typeToAuthDescription,
             String accountType) {
@@ -212,31 +259,40 @@
         bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
         bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
         setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
+        Log.d(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
+                + "selected account " + accountName + ", " + accountType);
         finish();
     }
 
     private void startChooseAccountTypeActivity() {
         final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
-        intent.putStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST,
-                getIntent().getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST));
+        intent.putStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
+                getIntent().getStringArrayListExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
         intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
-                getIntent().getBundleExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_ARRAYLIST));
+                getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
+        intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
+                getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
+        intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
+                getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
         startActivityForResult(intent, 0);
     }
 
     private static class AccountInfo {
         final Account account;
         final Drawable drawable;
+        private final boolean checked;
 
-        AccountInfo(Account account, Drawable drawable) {
+        AccountInfo(Account account, Drawable drawable, boolean checked) {
             this.account = account;
             this.drawable = drawable;
+            this.checked = checked;
         }
     }
 
     private static class ViewHolder {
         ImageView icon;
         TextView text;
+        ImageView checkmark;
     }
 
     private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
@@ -256,10 +312,11 @@
             ViewHolder holder;
 
             if (convertView == null) {
-                convertView = mLayoutInflater.inflate(R.layout.choose_account_row, null);
+                convertView = mLayoutInflater.inflate(R.layout.choose_selected_account_row, null);
                 holder = new ViewHolder();
                 holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
                 holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
+                holder.checkmark = (ImageView) convertView.findViewById(R.id.account_row_checkmark);
                 convertView.setTag(holder);
             } else {
                 holder = (ViewHolder) convertView.getTag();
@@ -267,7 +324,9 @@
 
             holder.text.setText(mInfos.get(position).account.name);
             holder.icon.setImageDrawable(mInfos.get(position).drawable);
-
+            final int displayCheckmark =
+                    mInfos.get(position).checked ? View.VISIBLE : View.INVISIBLE;
+            holder.checkmark.setVisibility(displayCheckmark);
             return convertView;
         }
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d78a7a3..d680f36 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1193,6 +1193,11 @@
         }
         super.setEnabled(enabled);
         prepareCursorControllers();
+        if (enabled) {
+            // Make sure IME is updated with current editor info.
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) imm.restartInput(this);
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index 29ad15b..f9c2cce 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -21,6 +21,8 @@
 import com.android.internal.widget.LockScreenWidgetCallback;
 import com.android.internal.widget.LockScreenWidgetInterface;
 
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -68,7 +70,7 @@
     private int mClientGeneration;
     private Metadata mMetadata = new Metadata();
     private boolean mAttached;
-    private ComponentName mClientName;
+    private PendingIntent mClientIntent;
     private int mTransportControlFlags;
     private int mPlayState;
     private AudioManager mAudioManager;
@@ -116,7 +118,7 @@
                     }
                 }
                 mClientGeneration = msg.arg1;
-                mClientName = (ComponentName) msg.obj;
+                mClientIntent = (PendingIntent) msg.obj;
                 break;
 
             }
@@ -174,12 +176,12 @@
             }
         }
 
-        public void setCurrentClientId(int clientGeneration, ComponentName clientEventReceiver,
+        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
                 boolean clearing) throws RemoteException {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_SET_GENERATION_ID,
-                    clientGeneration, (clearing ? 1 : 0), clientEventReceiver).sendToTarget();
+                    clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
             }
         }
     };
@@ -365,16 +367,27 @@
     }
 
     private void sendMediaButtonClick(int keyCode) {
-        // TODO: target to specific player based on mClientName
+        // use the registered PendingIntent that will be processed by the registered
+        //    media button event receiver, which is the component of mClientIntent
         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
         Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        getContext().sendOrderedBroadcast(intent, null);
+        try {
+            mClientIntent.send(getContext(), 0, intent);
+        } catch (CanceledException e) {
+            Log.e(TAG, "Error sending intent for media button down: "+e);
+            e.printStackTrace();
+        }
 
         keyEvent = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
         intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        getContext().sendOrderedBroadcast(intent, null);
+        try {
+            mClientIntent.send(getContext(), 0, intent);
+        } catch (CanceledException e) {
+            Log.e(TAG, "Error sending intent for media button up: "+e);
+            e.printStackTrace();
+        }
     }
 
     public void setCallback(LockScreenWidgetCallback callback) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 80741eb..9755f22 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1533,19 +1533,14 @@
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
                 android:excludeFromRecents="true"
                 android:exported="true"
-                android:theme="@android:style/Theme.Holo.Dialog"
+                android:theme="@android:style/Theme.Holo.DialogWhenLarge.NoActionBar"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
-                <intent-filter>
-                    <action android:name="android.intent.action.PICK" />
-                    <category android:name="android.intent.category.ACCOUNT" />
-                </intent-filter>
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
-                android:exported="true"
-                android:theme="@android:style/Theme.Holo.Dialog"
+                android:theme="@android:style/Theme.Holo.DialogWhenLarge.NoActionBar"
                 android:label="@string/choose_account_label"
                 android:process=":ui">
         </activity>
diff --git a/core/res/res/drawable-hdpi/ic_checkmark_holo_light.png b/core/res/res/drawable-hdpi/ic_checkmark_holo_light.png
new file mode 100644
index 0000000..2c6719b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_checkmark_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_checkmark_holo_light.png b/core/res/res/drawable-mdpi/ic_checkmark_holo_light.png
new file mode 100644
index 0000000..744e964
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_checkmark_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_checkmark_holo_light.png b/core/res/res/drawable-xhdpi/ic_checkmark_holo_light.png
new file mode 100644
index 0000000..1607f35
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_checkmark_holo_light.png
Binary files differ
diff --git a/core/res/res/layout/choose_account_type.xml b/core/res/res/layout/choose_account_type.xml
new file mode 100644
index 0000000..db96dc1
--- /dev/null
+++ b/core/res/res/layout/choose_account_type.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/layout/list_content.xml
+**
+** Copyright 2011, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingLeft="16dip"
+    android:paddingRight="16dip">
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_gravity="left"
+        android:text="@string/add_account_label"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip"
+        android:textColor="@android:color/holo_blue_light"
+    />
+
+    <View android:layout_height="3dip"
+          android:layout_width="match_parent"
+          android:background="#323232"/>
+
+    <ListView android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:drawSelectorOnTop="false"
+        android:scrollbarAlwaysDrawVerticalTrack="true" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/choose_selected_account_row.xml b/core/res/res/layout/choose_selected_account_row.xml
new file mode 100644
index 0000000..d88750d
--- /dev/null
+++ b/core/res/res/layout/choose_selected_account_row.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2011 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.
+ */
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingLeft="0dip"
+    android:paddingRight="0dip"
+    android:orientation="horizontal" >
+
+   <ImageView android:id="@+id/account_row_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:paddingRight="8dip" />
+
+   <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/account_row_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:gravity="center_vertical"
+        android:minHeight="?android:attr/listPreferredItemHeight" />
+
+    <ImageView android:id="@+id/account_row_checkmark"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:gravity="right"
+         android:layout_weight="2"
+         android:paddingRight="8dip"
+         android:src="@drawable/ic_checkmark_holo_light" />
+    
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/choose_type_and_account.xml b/core/res/res/layout/choose_type_and_account.xml
index 8be01b42..5a05126 100644
--- a/core/res/res/layout/choose_type_and_account.xml
+++ b/core/res/res/layout/choose_type_and_account.xml
@@ -24,21 +24,44 @@
     android:paddingLeft="16dip"
     android:paddingRight="16dip">
 
-    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@android:id/list"
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_gravity="left"
+        android:text="@string/choose_account_label"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip"
+        android:textColor="@android:color/holo_blue_light"
+    />
+
+    <View android:layout_height="3dip"
+          android:layout_width="match_parent"
+          android:background="#323232"/>
+    
+    <TextView android:id="@+id/description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_gravity="left|center_vertical"
+        android:text="@string/choose_account_text"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip"
+    />
+
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
         android:drawSelectorOnTop="false"
+        android:layout_weight="1"
         android:scrollbarAlwaysDrawVerticalTrack="true" />
 
     <Button android:id="@+id/addAccount"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="2"
         android:layout_marginLeft="2dip"
         android:layout_marginRight="2dip"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:textStyle="bold"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@string/add_account_button_label"
     />
 </LinearLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f75c7d5..e093fa9 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3094,6 +3094,12 @@
     <!-- Choose Account Activity label -->
     <string name="choose_account_label">Select an account</string>
 
+    <string name="add_account_label">"Add an account"</string>
+    <string name="choose_account_text">"Which account would you like to use?"</string>
+
+    <!-- Button label to add an account [CHAR LIMIT=20] -->
+    <string name="add_account_button_label">Add account</string>
+
     <!-- NumberPicker - accessibility support -->
     <!-- Description of the button to increment the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_increment_button">Increment</string>
@@ -3174,6 +3180,9 @@
 
     <!-- Slide lock screen -->
 
+    <!-- Description of the sliding handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
+    <string name="content_description_sliding_handle">"Sliding handle. Tap and hold."</string>
+
     <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_direction_up">Up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
     <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
@@ -3293,4 +3302,4 @@
     <!-- Delimeter used between each item in a textual list; for example "Alpha, Beta". [CHAR LIMIT=3] -->
     <string name="list_delimeter">", "</string>
 
-</resources>
+</resources>
\ No newline at end of file
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index cd8bb1d..a0881a7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -18,8 +18,10 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.os.Binder;
@@ -1684,17 +1686,42 @@
      * Register a component to be the sole receiver of MEDIA_BUTTON intents.
      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
      *      that will receive the media button intent. This broadcast receiver must be declared
-     *      in the application manifest.
+     *      in the application manifest. The package of the component must match that of
+     *      the context you're registering from.
      */
     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
         if (eventReceiver == null) {
             return;
         }
+        if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
+            Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
+                    "receiver and context package names don't match");
+            return;
+        }
+        // construct a PendingIntent for the media button and register it
+        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        //     the associated intent will be handled by the component being registered
+        mediaButtonIntent.setComponent(eventReceiver);
+        PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
+        registerMediaButtonIntent(pi, eventReceiver);
+    }
+
+    /**
+     * @hide
+     * no-op if (pi == null) or (eventReceiver == null)
+     */
+    public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
+        if ((pi == null) || (eventReceiver == null)) {
+            Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
+            return;
+        }
         IAudioService service = getService();
         try {
-            service.registerMediaButtonEventReceiver(eventReceiver);
+            // pi != null
+            service.registerMediaButtonIntent(pi, eventReceiver);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerMediaButtonEventReceiver"+e);
+            Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
         }
     }
 
@@ -1707,14 +1734,26 @@
         if (eventReceiver == null) {
             return;
         }
-        IAudioService service = getService();
-        try {
-            service.unregisterMediaButtonEventReceiver(eventReceiver);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiver"+e);
-        }
+        // construct a PendingIntent for the media button and unregister it
+        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        //     the associated intent will be handled by the component being registered
+        mediaButtonIntent.setComponent(eventReceiver);
+        PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
+        unregisterMediaButtonIntent(pi, eventReceiver);
     }
 
+    /**
+     * @hide
+     */
+    public void unregisterMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
+        IAudioService service = getService();
+        try {
+            service.unregisterMediaButtonIntent(pi, eventReceiver);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
+        }
+    }
 
     /**
      * Registers the remote control client for providing information to display on the remote
@@ -1724,14 +1763,13 @@
      * @see RemoteControlClient
      */
     public void registerRemoteControlClient(RemoteControlClient rcClient) {
-        if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
+        if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
         IAudioService service = getService();
         try {
-            service.registerRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
+            service.registerRemoteControlClient(rcClient.getRcMediaIntent(),   /* mediaIntent   */
                     rcClient.getIRemoteControlClient(),                        /* rcClient      */
-                    rcClient.toString(),                                       /* clientName    */
                     // used to match media button event receiver and audio focus
                     mContext.getPackageName());                                /* packageName   */
         } catch (RemoteException e) {
@@ -1746,13 +1784,13 @@
      * @see #registerRemoteControlClient(RemoteControlClient)
      */
     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
-        if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
+        if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
         IAudioService service = getService();
         try {
-            service.unregisterRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
-                    rcClient.getIRemoteControlClient());                         /* rcClient      */
+            service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent   */
+                    rcClient.getIRemoteControlClient());                       /* rcClient      */
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index db27cfd..8895c9e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -18,6 +18,8 @@
 
 import android.app.ActivityManagerNative;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -35,6 +37,7 @@
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
@@ -2084,7 +2087,7 @@
             }
         }
 
-        private void persistMediaButtonReceiver(ComponentName receiver) {
+        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
             Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
                     receiver == null ? "" : receiver.flattenToString());
         }
@@ -2201,7 +2204,7 @@
                     break;
 
                 case MSG_PERSIST_MEDIABUTTONRECEIVER:
-                    persistMediaButtonReceiver( (ComponentName) msg.obj );
+                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
                     break;
 
                 case MSG_RCDISPLAY_CLEAR:
@@ -2894,14 +2897,22 @@
                 }
                 synchronized(mRCStack) {
                     if (!mRCStack.empty()) {
-                        // create a new intent specifically aimed at the current registered listener
+                        // create a new intent to fill in the extras of the registered PendingIntent
                         Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-                        targetedIntent.putExtras(intent.getExtras());
-                        targetedIntent.setComponent(mRCStack.peek().mReceiverComponent);
-                        // trap the current broadcast
-                        abortBroadcast();
-                        //Log.v(TAG, " Sending intent" + targetedIntent);
-                        context.sendBroadcast(targetedIntent, null);
+                        Bundle extras = intent.getExtras();
+                        if (extras != null) {
+                            targetedIntent.putExtras(extras);
+                            // trap the current broadcast
+                            abortBroadcast();
+                            //Log.v(TAG, " Sending intent" + targetedIntent);
+                            // send the intent that was registered by the client
+                            try {
+                                mRCStack.peek().mMediaIntent.send(context, 0, targetedIntent);
+                            } catch (CanceledException e) {
+                                Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
+                                e.printStackTrace();
+                            }
+                        }
                     }
                 }
             }
@@ -2936,18 +2947,18 @@
      */
     private class RcClientDeathHandler implements IBinder.DeathRecipient {
         private IBinder mCb; // To be notified of client's death
-        private ComponentName mRcEventReceiver;
+        private PendingIntent mMediaIntent;
 
-        RcClientDeathHandler(IBinder cb, ComponentName eventReceiver) {
+        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
             mCb = cb;
-            mRcEventReceiver = eventReceiver;
+            mMediaIntent = pi;
         }
 
         public void binderDied() {
             Log.w(TAG, "  RemoteControlClient died");
             // remote control client died, make sure the displays don't use it anymore
             //  by setting its remote control client to null
-            registerRemoteControlClient(mRcEventReceiver, null, null, null/*ignored*/);
+            registerRemoteControlClient(mMediaIntent, null, null/*ignored*/);
         }
 
         public IBinder getBinder() {
@@ -2956,18 +2967,29 @@
     }
 
     private static class RemoteControlStackEntry {
-        /** the target for the ACTION_MEDIA_BUTTON events */
-        public ComponentName mReceiverComponent;// always non null
+        /**
+         * The target for the ACTION_MEDIA_BUTTON events.
+         * Always non null.
+         */
+        public PendingIntent mMediaIntent;
+        /**
+         * The registered media button event receiver.
+         * Always non null.
+         */
+        public ComponentName mReceiverComponent;
         public String mCallingPackageName;
-        public String mRcClientName;
         public int mCallingUid;
-
-        /** provides access to the information to display on the remote control */
+        /**
+         * Provides access to the information to display on the remote control.
+         * May be null (when a media button event receiver is registered,
+         *     but no remote control client has been registered) */
         public IRemoteControlClient mRcClient;
         public RcClientDeathHandler mRcClientDeathHandler;
 
-        public RemoteControlStackEntry(ComponentName r) {
-            mReceiverComponent = r;
+        /** precondition: mediaIntent != null, eventReceiver != null */
+        public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
+            mMediaIntent = mediaIntent;
+            mReceiverComponent = eventReceiver;
             mCallingUid = -1;
             mRcClient = null;
         }
@@ -3003,7 +3025,8 @@
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
                 RemoteControlStackEntry rcse = stackIterator.next();
-                pw.println("     receiver: " + rcse.mReceiverComponent +
+                pw.println("  pi: " + rcse.mMediaIntent +
+                        "  -- ercvr: " + rcse.mReceiverComponent +
                         "  -- client: " + rcse.mRcClient +
                         "  -- uid: " + rcse.mCallingUid);
             }
@@ -3035,7 +3058,6 @@
                     mAudioHandler.sendMessage(
                             mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
                                     null));
-                    return;
                 } else if (oldTop != mRCStack.peek()) {
                     // the top of the stack has changed, save it in the system settings
                     // by posting a message to persist it
@@ -3049,25 +3071,32 @@
 
     /**
      * Helper function:
-     * Restore remote control receiver from the system settings
+     * Restore remote control receiver from the system settings.
      */
     private void restoreMediaButtonReceiver() {
         String receiverName = Settings.System.getString(mContentResolver,
                 Settings.System.MEDIA_BUTTON_RECEIVER);
         if ((null != receiverName) && !receiverName.isEmpty()) {
-            ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
-            registerMediaButtonEventReceiver(receiverComponentName);
+            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
+            // construct a PendingIntent targeted to the restored component name
+            // for the media button and register it
+            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+            //     the associated intent will be handled by the component being registered
+            mediaButtonIntent.setComponent(eventReceiver);
+            PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
+            registerMediaButtonIntent(pi, eventReceiver);
         }
-        // upon restoring (e.g. after boot), do we want to refresh all remotes?
     }
 
     /**
      * Helper function:
-     * Set the new remote control receiver at the top of the RC focus stack
+     * Set the new remote control receiver at the top of the RC focus stack.
+     * precondition: mediaIntent != null, target != null
      */
-    private void pushMediaButtonReceiver(ComponentName newReceiver) {
+    private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) {
         // already at top of stack?
-        if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) {
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
             return;
         }
         Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
@@ -3075,31 +3104,32 @@
         boolean wasInsideStack = false;
         while(stackIterator.hasNext()) {
             rcse = (RemoteControlStackEntry)stackIterator.next();
-            if(rcse.mReceiverComponent.equals(newReceiver)) {
+            if(rcse.mMediaIntent.equals(mediaIntent)) {
                 wasInsideStack = true;
                 stackIterator.remove();
                 break;
             }
         }
         if (!wasInsideStack) {
-            rcse = new RemoteControlStackEntry(newReceiver);
+            rcse = new RemoteControlStackEntry(mediaIntent, target);
         }
         mRCStack.push(rcse);
 
         // post message to persist the default media button receiver
         mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
-                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, newReceiver/*obj*/) );
+                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
     }
 
     /**
      * Helper function:
-     * Remove the remote control receiver from the RC focus stack
+     * Remove the remote control receiver from the RC focus stack.
+     * precondition: pi != null
      */
-    private void removeMediaButtonReceiver(ComponentName newReceiver) {
+    private void removeMediaButtonReceiver(PendingIntent pi) {
         Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
         while(stackIterator.hasNext()) {
             RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
-            if(rcse.mReceiverComponent.equals(newReceiver)) {
+            if(rcse.mMediaIntent.equals(pi)) {
                 stackIterator.remove();
                 break;
             }
@@ -3110,8 +3140,8 @@
      * Helper function:
      * Called synchronized on mRCStack
      */
-    private boolean isCurrentRcController(ComponentName eventReceiver) {
-        if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(eventReceiver)) {
+    private boolean isCurrentRcController(PendingIntent pi) {
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
             return true;
         }
         return false;
@@ -3124,12 +3154,12 @@
      * Update the remote control displays with the new "focused" client generation
      */
     private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
-            ComponentName newClientEventReceiver, boolean clearing) {
+            PendingIntent newMediaIntent, boolean clearing) {
         // NOTE: Only one IRemoteControlDisplay supported in this implementation
         if (mRcDisplay != null) {
             try {
                 mRcDisplay.setCurrentClientId(
-                        newClientGeneration, newClientEventReceiver, clearing);
+                        newClientGeneration, newMediaIntent, clearing);
             } catch (RemoteException e) {
                 Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
                 // if we had a display before, stop monitoring its death
@@ -3167,10 +3197,9 @@
      *    where the display should be cleared.
      */
     private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
-            ComponentName newClientEventReceiver, boolean clearing) {
+            PendingIntent newMediaIntent, boolean clearing) {
         // send the new valid client generation ID to all displays
-        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newClientEventReceiver,
-                clearing);
+        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
         // send the new valid client generation ID to all clients
         setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
     }
@@ -3186,7 +3215,7 @@
                 mCurrentRcClientGen++;
                 // synchronously update the displays and clients with the new client generation
                 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                        null /*event receiver*/, true /*clearing*/);
+                        null /*newMediaIntent*/, true /*clearing*/);
             }
         }
     }
@@ -3204,7 +3233,7 @@
                     // synchronously update the displays and clients with
                     //      the new client generation
                     setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                            rcse.mReceiverComponent /*event receiver*/,
+                            rcse.mMediaIntent /*newMediaIntent*/,
                             false /*clearing*/);
 
                     // tell the current client that it needs to send info
@@ -3301,27 +3330,34 @@
         updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
     }
 
-    /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
-    public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
-        Log.i(TAG, "  Remote Control   registerMediaButtonEventReceiver() for " + eventReceiver);
+    /** 
+     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
+     * precondition: mediaIntent != null, target != null
+     */
+    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
+        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
 
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                pushMediaButtonReceiver(eventReceiver);
+                pushMediaButtonReceiver(mediaIntent, eventReceiver);
                 // new RC client, assume every type of information shall be queried
                 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
         }
     }
 
-    /** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */
-    public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
-        Log.i(TAG, "  Remote Control   unregisterMediaButtonEventReceiver() for " + eventReceiver);
+    /** 
+     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
+     * precondition: mediaIntent != null, eventReceiver != null
+     */
+    public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
+    {
+        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
 
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                boolean topOfStackWillChange = isCurrentRcController(eventReceiver);
-                removeMediaButtonReceiver(eventReceiver);
+                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+                removeMediaButtonReceiver(mediaIntent);
                 if (topOfStackWillChange) {
                     // current RC client will change, assume every type of info needs to be queried
                     checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
@@ -3331,8 +3367,8 @@
     }
 
     /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
-    public void registerRemoteControlClient(ComponentName eventReceiver,
-            IRemoteControlClient rcClient, String clientName, String callingPackageName) {
+    public void registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPackageName) {
         if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
@@ -3340,7 +3376,7 @@
                 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
                 while(stackIterator.hasNext()) {
                     RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mReceiverComponent.equals(eventReceiver)) {
+                    if(rcse.mMediaIntent.equals(mediaIntent)) {
                         // already had a remote control client?
                         if (rcse.mRcClientDeathHandler != null) {
                             // stop monitoring the old client's death
@@ -3357,7 +3393,6 @@
                             }
                         }
                         rcse.mCallingPackageName = callingPackageName;
-                        rcse.mRcClientName = clientName;
                         rcse.mCallingUid = Binder.getCallingUid();
                         if (rcClient == null) {
                             rcse.mRcClientDeathHandler = null;
@@ -3366,7 +3401,7 @@
                         // monitor the new client's death
                         IBinder b = rcClient.asBinder();
                         RcClientDeathHandler rcdh =
-                                new RcClientDeathHandler(b, rcse.mReceiverComponent);
+                                new RcClientDeathHandler(b, rcse.mMediaIntent);
                         try {
                             b.linkToDeath(rcdh, 0);
                         } catch (RemoteException e) {
@@ -3380,7 +3415,7 @@
                 }
                 // if the eventReceiver is at the top of the stack
                 // then check for potential refresh of the remote controls
-                if (isCurrentRcController(eventReceiver)) {
+                if (isCurrentRcController(mediaIntent)) {
                     checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }
@@ -3388,24 +3423,23 @@
     }
 
     /**
-     * see AudioManager.unregisterRemoteControlClient(ComponentName eventReceiver, ...)
+     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
      * rcClient is guaranteed non-null
      */
-    public void unregisterRemoteControlClient(ComponentName eventReceiver,
+    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
             IRemoteControlClient rcClient) {
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
                 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
                 while(stackIterator.hasNext()) {
                     RemoteControlStackEntry rcse = stackIterator.next();
-                    if ((rcse.mReceiverComponent.equals(eventReceiver))
+                    if ((rcse.mMediaIntent.equals(mediaIntent))
                             && rcClient.equals(rcse.mRcClient)) {
                         // we found the IRemoteControlClient to unregister
                         // stop monitoring its death
                         rcse.unlinkToRcClientDeath();
                         // reset the client-related fields
                         rcse.mRcClient = null;
-                        rcse.mRcClientName = null;
                         rcse.mRcClientDeathHandler = null;
                         rcse.mCallingPackageName = null;
                     }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7bf9814..5294d36 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.media.IAudioFocusDispatcher;
 import android.media.IRemoteControlClient;
@@ -85,13 +86,12 @@
     
     void unregisterAudioFocusClient(String clientId);
 
-    void registerMediaButtonEventReceiver(in ComponentName eventReceiver);
+    oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
+    oneway void unregisterMediaButtonIntent(in PendingIntent pi,  in ComponentName c);
 
-    void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
-
-    oneway void registerRemoteControlClient(in ComponentName eventReceiver,
-           in IRemoteControlClient rcClient, in String clientName, in String callingPackageName);
-    oneway void unregisterRemoteControlClient(in ComponentName eventReceiver,
+    oneway void registerRemoteControlClient(in PendingIntent mediaIntent,
+           in IRemoteControlClient rcClient, in String callingPackageName);
+    oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
            in IRemoteControlClient rcClient);
 
     oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd);
diff --git a/media/java/android/media/IRemoteControlDisplay.aidl b/media/java/android/media/IRemoteControlDisplay.aidl
index fd50b7e..e15b07c 100644
--- a/media/java/android/media/IRemoteControlDisplay.aidl
+++ b/media/java/android/media/IRemoteControlDisplay.aidl
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.graphics.Bitmap;
 import android.os.Bundle;
@@ -31,14 +32,12 @@
     /**
      * Sets the generation counter of the current client that is displayed on the remote control.
      * @param clientGeneration the new RemoteControlClient generation
-     * @param clientEventReceiver the media button event receiver associated with the client.
-     *    May be null, which implies there is no registered media button event receiver. This
-     *    parameter is supplied as an optimization so a display can directly target media button
-     *    events to the client.
+     * @param clientMediaIntent the PendingIntent associated with the client.
+     *    May be null, which implies there is no registered media button event receiver.
      * @param clearing true if the new client generation value maps to a remote control update
      *    where the display should be cleared.
      */
-    void setCurrentClientId(int clientGeneration, in ComponentName clientEventReceiver,
+    void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent,
             boolean clearing);
 
     void setPlaybackState(int generationId, int state);
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index cdebba0..5dea87f 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -34,6 +34,7 @@
 import java.lang.IllegalArgumentException;
 
 /**
+ * TODO javadoc update for ComponentName - PendingIntent change
  * RemoteControlClient enables exposing information meant to be consumed by remote controls
  * capable of displaying metadata, artwork and media transport control buttons.
  * A remote control client object is associated with a media button event receiver. This
@@ -205,50 +206,6 @@
     public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
 
     /**
-     * @hide
-     * TODO remove after modifying known (internal) media apps using this API
-     * Class constructor.
-     * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
-     *     been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
-     *     before this new RemoteControlClient can itself be registered with
-     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
-     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
-     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
-     */
-    public RemoteControlClient(ComponentName mediaButtonEventReceiver) {
-        mRcEventReceiver = mediaButtonEventReceiver;
-
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else {
-            mEventHandler = null;
-            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
-        }
-    }
-
-    /**
-     * @hide
-     * TODO remove after modifying known (internal) media apps using this API
-     * Class constructor for a remote control client whose internal event handling
-     * happens on a user-provided Looper.
-     * @param mediaButtonEventReceiver The receiver for the media button events. It needs to have
-     *     been registered with {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
-     *     before this new RemoteControlClient can itself be registered with
-     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
-     * @param looper The Looper running the event loop.
-     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
-     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
-     */
-    public RemoteControlClient(ComponentName mediaButtonEventReceiver, Looper looper) {
-        mRcEventReceiver = mediaButtonEventReceiver;
-
-        mEventHandler = new EventHandler(this, looper);
-    }
-
-    /**
      * Class constructor.
      * @param mediaButtonIntent The intent that will be sent for the media button events sent
      *     by remote controls.
@@ -262,8 +219,7 @@
      * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
      */
     public RemoteControlClient(PendingIntent mediaButtonIntent) {
-        // TODO implement using PendingIntent instead of ComponentName
-        mRcEventReceiver = null;
+        mRcMediaIntent = mediaButtonIntent;
 
         Looper looper;
         if ((looper = Looper.myLooper()) != null) {
@@ -292,8 +248,7 @@
      * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
      */
     public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
-        // TODO implement using PendingIntent instead of ComponentName
-        mRcEventReceiver = null;
+        mRcMediaIntent = mediaButtonIntent;
 
         mEventHandler = new EventHandler(this, looper);
     }
@@ -614,9 +569,10 @@
     private int mInternalClientGenId = -2;
 
     /**
-     * The media button event receiver associated with this remote control client
+     * The media button intent description associated with this remote control client
+     * (can / should include target component for intent handling)
      */
-    private final ComponentName mRcEventReceiver;
+    private final PendingIntent mRcMediaIntent;
 
     /**
      * The remote control display to which this client will send information.
@@ -626,10 +582,10 @@
 
     /**
      * @hide
-     * Accessor to media button event receiver
+     * Accessor to media button intent description (includes target component)
      */
-    public ComponentName getRcEventReceiver() {
-        return mRcEventReceiver;
+    public PendingIntent getRcMediaIntent() {
+        return mRcMediaIntent;
     }
     /**
      * @hide
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index f84cc19..2fe22ff 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -69,6 +69,12 @@
 
     </FrameLayout>
 
+    <include layout="@layout/status_bar_no_recent_apps"
+        android:id="@+id/recents_no_apps"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <View android:id="@+id/recents_dismiss_button"
         android:layout_width="80px"
         android:layout_height="@*android:dimen/status_bar_height"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index ed9ea7a..4d49077 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -67,6 +67,12 @@
 
     </FrameLayout>
 
+    <include layout="@layout/status_bar_no_recent_apps"
+        android:id="@+id/recents_no_apps"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <View android:id="@+id/recents_dismiss_button"
         android:layout_width="80px"
         android:layout_height="@*android:dimen/status_bar_height"
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
new file mode 100644
index 0000000..47ffb83
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="24dp"
+        android:textColor="#ffffffff"
+        android:text="@string/status_bar_no_recent_apps"
+        android:gravity="center_horizontal"
+        android:layout_gravity="center"
+    />
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bad7e1f..b9e6d78 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -41,6 +41,10 @@
     <!-- Title shown in recents popup for inspecting an application's properties -->
     <string name="status_bar_recent_inspect_item_title">App info</string>
 
+    <!-- Message shown in the middle of the screen after clicking on the recent apps button
+         when there are no recent apps to show [CHAR LIMIT=45]-->
+    <string name="status_bar_no_recent_apps">No recent apps</string>
+
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing.  [CHAR LIMIT=40]-->
     <string name="status_bar_no_notifications_title">No notifications</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index 9749a1d..fbf00d2 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -38,17 +38,20 @@
     View mRootView;
     View mScrimView;
     View mContentView;
+    View mNoRecentAppsView;
     AnimatorSet mContentAnim;
     Animator.AnimatorListener mListener;
 
     // the panel will start to appear this many px from the end
     final int HYPERSPACE_OFFRAMP = 200;
 
-    public Choreographer(View root, View scrim, View content, Animator.AnimatorListener listener) {
+    public Choreographer(View root, View scrim, View content,
+            View noRecentApps, Animator.AnimatorListener listener) {
         mRootView = root;
         mScrimView = scrim;
         mContentView = content;
         mListener = listener;
+        mNoRecentAppsView = noRecentApps;
     }
 
     void createAnimation(boolean appearing) {
@@ -81,8 +84,24 @@
                 : new android.view.animation.DecelerateInterpolator(1.0f));
         glowAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
 
+        Animator noRecentAppsFadeAnim = null;
+        if (mNoRecentAppsView != null &&  // doesn't exist on large devices
+                mNoRecentAppsView.getVisibility() == View.VISIBLE) {
+            noRecentAppsFadeAnim = ObjectAnimator.ofFloat(mNoRecentAppsView, "alpha",
+                    mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
+            noRecentAppsFadeAnim.setInterpolator(appearing
+                    ? new android.view.animation.AccelerateInterpolator(1.0f)
+                    : new android.view.animation.DecelerateInterpolator(1.0f));
+            noRecentAppsFadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
+        }
+
         mContentAnim = new AnimatorSet();
         final Builder builder = mContentAnim.play(glowAnim).with(posAnim);
+
+        if (noRecentAppsFadeAnim != null) {
+            builder.with(noRecentAppsFadeAnim);
+        }
+
         Drawable background = mScrimView.getBackground();
         if (background != null) {
             Animator bgAnim = ObjectAnimator.ofInt(background,
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 0621b22..6fdc534 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -83,6 +83,7 @@
     private int mIconDpi;
     private View mRecentsScrim;
     private View mRecentsGlowView;
+    private View mRecentsNoApps;
     private ViewGroup mRecentsContainer;
     private Bitmap mDefaultThumbnailBackground;
 
@@ -373,8 +374,9 @@
 
 
         mRecentsGlowView = findViewById(R.id.recents_glow);
-        mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
-        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
+        mRecentsScrim = findViewById(R.id.recents_bg_protect);
+        mRecentsNoApps = findViewById(R.id.recents_no_apps);
+        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, mRecentsNoApps, this);
         mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
         mRecentsDismissButton.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
@@ -581,6 +583,9 @@
             mThumbnailLoader.cancel(false);
             mThumbnailLoader = null;
         }
+        if (mRecentsNoApps != null) { // doesn't exist on large devices
+            mRecentsNoApps.setVisibility(View.INVISIBLE);
+        }
         mActivityDescriptions = getRecentTasks();
         for (ActivityDescription ad : mActivityDescriptions) {
             ad.setThumbnail(mDefaultThumbnailBackground);
@@ -647,7 +652,11 @@
         } else {
             // Immediately hide this panel
             if (DEBUG) Log.v(TAG, "Nothing to show");
-            hide(false);
+            if (mRecentsNoApps != null) { // doesn't exist on large devices
+                mRecentsNoApps.setVisibility(View.VISIBLE);
+            } else {
+                hide(false);
+            }
         }
     }