Merge "Fix invalidation roundoff error with old animations"
diff --git a/Android.mk b/Android.mk
index fdf0933..d4dc088 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,7 +183,8 @@
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
-	media/java/android/media/IRemoteControlClientDispatcher.aidl \
+	media/java/android/media/IRemoteControlClient.aidl \
+	media/java/android/media/IRemoteControlDisplay.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2593065..3cec66f 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -105,6 +105,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/SystemUI_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/R/com/android/systemui/R.java)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.P)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.P)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index cd85eea..033cccb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -958,6 +958,8 @@
     field public static final int textAppearanceLarge = 16842816; // 0x1010040
     field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
     field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
+    field public static final int textAppearanceListItem = 16843688; // 0x10103a8
+    field public static final int textAppearanceListItemSmall = 16843689; // 0x10103a9
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
@@ -4224,6 +4226,7 @@
     method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public java.lang.String getName();
+    method public int getProfileConnectionState(int);
     method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
     method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
     method public int getScanMode();
@@ -7205,6 +7208,7 @@
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
     method public synchronized void close();
+    method public java.lang.String getDatabaseName();
     method public synchronized android.database.sqlite.SQLiteDatabase getReadableDatabase();
     method public synchronized android.database.sqlite.SQLiteDatabase getWritableDatabase();
     method public abstract void onCreate(android.database.sqlite.SQLiteDatabase);
@@ -9362,6 +9366,7 @@
     field public static final int FOCUS_DISTANCE_NEAR_INDEX = 0; // 0x0
     field public static final int FOCUS_DISTANCE_OPTIMAL_INDEX = 1; // 0x1
     field public static final java.lang.String FOCUS_MODE_AUTO = "auto";
+    field public static final java.lang.String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
     field public static final java.lang.String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video";
     field public static final java.lang.String FOCUS_MODE_EDOF = "edof";
     field public static final java.lang.String FOCUS_MODE_FIXED = "fixed";
@@ -18400,6 +18405,7 @@
 
   public class WallpaperService.Engine {
     ctor public WallpaperService.Engine();
+    method protected void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public int getDesiredMinimumHeight();
     method public int getDesiredMinimumWidth();
     method public android.view.SurfaceHolder getSurfaceHolder();
@@ -23503,6 +23509,7 @@
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method protected void setDefaultWindowFormat(int);
+    method public void setDimAmount(float);
     method public abstract void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public abstract void setFeatureDrawableAlpha(int, int);
     method public abstract void setFeatureDrawableResource(int, int);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 8901fc8..7799779 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1541,6 +1541,15 @@
             return true;
         }
 
+        case SHOW_BOOT_MESSAGE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            CharSequence msg = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
+            boolean always = data.readInt() != 0;
+            showBootMessage(msg, always);
+            reply.writeNoException();
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3483,5 +3492,17 @@
         return res;
     }
 
+    public void showBootMessage(CharSequence msg, boolean always) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        TextUtils.writeToParcel(msg, data, 0);
+        data.writeInt(always ? 1 : 0);
+        mRemote.transact(SHOW_BOOT_MESSAGE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e376220..6fb7965 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4091,7 +4091,7 @@
     final void removeDeadProvider(String name, IContentProvider provider) {
         synchronized(mProviderMap) {
             ProviderClientRecord pr = mProviderMap.get(name);
-            if (pr.mProvider.asBinder() == provider.asBinder()) {
+            if (pr != null && pr.mProvider.asBinder() == provider.asBinder()) {
                 Slog.i(TAG, "Removing dead content provider: " + name);
                 ProviderClientRecord removed = mProviderMap.remove(name);
                 if (removed != null) {
@@ -4101,17 +4101,6 @@
         }
     }
 
-    final void removeDeadProviderLocked(String name, IContentProvider provider) {
-        ProviderClientRecord pr = mProviderMap.get(name);
-        if (pr.mProvider.asBinder() == provider.asBinder()) {
-            Slog.i(TAG, "Removing dead content provider: " + name);
-            ProviderClientRecord removed = mProviderMap.remove(name);
-            if (removed != null) {
-                removed.mProvider.asBinder().unlinkToDeath(removed, 0);
-            }
-        }
-    }
-
     private IContentProvider installProvider(Context context,
             IContentProvider provider, ProviderInfo info, boolean noisy) {
         ContentProvider localProvider = null;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 49f8449..27dd691 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -370,6 +370,8 @@
 
     public long[] getProcessPss(int[] pids) throws RemoteException;
 
+    public void showBootMessage(CharSequence msg, boolean always) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -599,4 +601,5 @@
     int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
     int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135;
     int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
+    int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 28bc424..2236928 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -774,6 +774,32 @@
     }
 
     /**
+     * Get the current connection state of a profile.
+     * This function can be used to check whether the local Bluetooth adapter
+     * is connected to any remote device for a specific profile.
+     * Profile can be one of {@link BluetoothProfile#HEADSET},
+     * {@link BluetoothProfile#A2DP}.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+     *
+     * <p> Return value can be one of
+     * {@link BluetoothProfile#STATE_DISCONNECTED},
+     * {@link BluetoothProfile#STATE_CONNECTING},
+     * {@link BluetoothProfile#STATE_CONNECTED},
+     * {@link BluetoothProfile#STATE_DISCONNECTING}
+     */
+    public int getProfileConnectionState(int profile) {
+        if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
+        try {
+            return mService.getProfileConnectionState(profile);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getProfileConnectionState:", e);
+        }
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+    /**
      * Picks RFCOMM channels until none are left.
      * Avoids reserved channels.
      */
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 6cd81fd..58b3868 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -83,6 +83,12 @@
     public static final int PAN = 5;
 
     /**
+     * PBAP
+     * @hide
+     */
+    public static final int PBAP = 6;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 48dfed8..d4e7f7d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -53,6 +53,7 @@
     byte[] readOutOfBandData();
 
     int getAdapterConnectionState();
+    int getProfileConnectionState(int profile);
     boolean changeApplicationBluetoothState(boolean on,
                                 in IBluetoothStateChangeCallback callback, in
                                 IBinder b);
@@ -121,5 +122,5 @@
     List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
     int getHealthDeviceConnectionState(in BluetoothDevice device);
 
-    void sendConnectionStateChange(in BluetoothDevice device, int state, int prevState);
+    void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d7607e3..08aef16 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -320,7 +320,13 @@
     boolean isSafeMode();
     void systemReady();
     boolean hasSystemUidErrors();
-    
+
+    /**
+     * Ask the package manager to perform boot-time dex-opt of all
+     * existing packages.
+     */
+    void performBootDexOpt();
+
     /**
      * Ask the package manager to perform dex-opt (if needed) on the given
      * package, if it already hasn't done mode.  Only does this if running
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index e2befca..56cf948 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -100,6 +100,14 @@
     }
 
     /**
+     * Return the name of the SQLite database being opened, as given tp
+     * the constructor.
+     */
+    public String getDatabaseName() {
+        return mName;
+    }
+
+    /**
      * Create and/or open a database that will be used for reading and writing.
      * The first time this is called, the database will be opened and
      * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 08bb133..a41a330 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1674,7 +1674,6 @@
          * the focus mode to other modes.
          *
          * @see #FOCUS_MODE_CONTINUOUS_VIDEO
-         * @hide
          */
         public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 554afd2..03cba3d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2815,6 +2815,16 @@
         public static final String TTS_DEFAULT_VARIANT = "tts_default_variant";
 
         /**
+         * Stores the default tts locales on a per engine basis. Stored as
+         * a comma seperated list of values, each value being of the form
+         * {@code engine_name:locale} for example,
+         * {@code com.foo.ttsengine:eng-USA,com.bar.ttsengine:esp-ESP}.
+         *
+         * @hide
+         */
+        public static final String TTS_DEFAULT_LOCALE = "tts_default_locale";
+
+        /**
          * Space delimited list of plugin packages that are enabled.
          */
         public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 8c04853..c4cb3a5 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -523,7 +523,8 @@
 
             if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
 
-            mBluetoothService.sendConnectionStateChange(device, state, prevState);
+            mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.A2DP, state,
+                                                        prevState);
         }
     }
 
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 105ff332..51c995e 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHealth;
 import android.bluetooth.BluetoothHealthAppConfiguration;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.IBluetoothHealthCallback;
 import android.content.Context;
 import android.os.Handler;
@@ -567,7 +568,8 @@
     private void updateAndSendIntent(BluetoothDevice device, int prevDeviceState,
             int newDeviceState) {
         mHealthDevices.put(device, newDeviceState);
-        mBluetoothService.sendConnectionStateChange(device, prevDeviceState, newDeviceState);
+        mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.HEALTH,
+                                                    newDeviceState, prevDeviceState);
     }
 
     /**
diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java
index 247e297..31764b0 100644
--- a/core/java/android/server/BluetoothInputProfileHandler.java
+++ b/core/java/android/server/BluetoothInputProfileHandler.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothDeviceProfileState;
 import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfileState;
 import android.content.Context;
 import android.content.Intent;
@@ -191,7 +192,8 @@
         mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
 
         debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
-        mBluetoothService.sendConnectionStateChange(device, state, prevState);
+        mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.INPUT_DEVICE, state,
+                                                    prevState);
     }
 
     void handleInputDevicePropertyChange(String address, boolean connected) {
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index 37cfdc4..bfad747 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -19,6 +19,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothTetheringDataTracker;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -303,7 +304,8 @@
         mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
 
         debugLog("Pan Device state : device: " + device + " State:" + prevState + "->" + state);
-        mBluetoothService.sendConnectionStateChange(device, state, prevState);
+        mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.PAN, state,
+                                                    prevState);
     }
 
     private class BluetoothPanDevice {
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index ee14673..e942969 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -166,6 +166,7 @@
     private static final String INCOMING_CONNECTION_FILE =
       "/data/misc/bluetooth/incoming_connection.conf";
     private HashMap<String, Pair<Integer, String>> mIncomingConnections;
+    private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
 
     private static class RemoteService {
         public String address;
@@ -237,6 +238,7 @@
         mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
         mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this);
         mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
+        mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
     }
 
     public static synchronized String readDockBluetoothAddress() {
@@ -600,6 +602,11 @@
      * It inits bond state and profile state before STATE_ON intent is broadcasted.
      */
     /*package*/ void initBluetoothAfterTurningOn() {
+        String discoverable = getProperty("Discoverable", false);
+        String timeout = getProperty("DiscoverableTimeout", false);
+        if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
+            setAdapterPropertyBooleanNative("Discoverable", 0);
+        }
         mBondState.initBondState();
         initProfileState();
     }
@@ -1742,6 +1749,19 @@
         dumpInputDeviceProfile(pw);
         dumpPanProfile(pw);
         dumpApplicationServiceRecords(pw);
+        dumpProfileState(pw);
+    }
+
+    private void dumpProfileState(PrintWriter pw) {
+        pw.println("\n--Profile State dump--");
+        pw.println("\n Headset profile state:" +
+                mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
+        pw.println("\n A2dp profile state:" +
+                mAdapter.getProfileConnectionState(BluetoothProfile.A2DP));
+        pw.println("\n HID profile state:" +
+                mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE));
+        pw.println("\n PAN profile state:" +
+                mAdapter.getProfileConnectionState(BluetoothProfile.PAN));
     }
 
     private void dumpHeadsetService(PrintWriter pw) {
@@ -2443,23 +2463,85 @@
         return mAdapterConnectionState;
     }
 
-    public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
-                                                        int prevState) {
+    public int getProfileConnectionState(int profile) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
+        Pair<Integer, Integer> state = mProfileConnectionState.get(profile);
+        if (state == null) return BluetoothProfile.STATE_DISCONNECTED;
+
+        return state.first;
+    }
+
+    private void updateProfileConnectionState(int profile, int newState, int oldState) {
+        // mProfileConnectionState is a hashmap -
+        // <Integer, Pair<Integer, Integer>>
+        // The key is the profile, the value is a pair. first element
+        // is the state and the second element is the number of devices
+        // in that state.
+        int numDev = 1;
+        int newHashState = newState;
+        boolean update = true;
+
+        // The following conditions are considered in this function:
+        // 1. If there is no record of profile and state - update
+        // 2. If a new device's state is current hash state - increment
+        //    number of devices in the state.
+        // 3. If a state change has happened to Connected or Connecting
+        //    (if current state is not connected), update.
+        // 4. If numDevices is 1 and that device state is being updated, update
+        // 5. If numDevices is > 1 and one of the devices is changing state,
+        //    decrement numDevices but maintain oldState if it is Connected or
+        //    Connecting
+        Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
+        if (stateNumDev != null) {
+            int currHashState = stateNumDev.first;
+            numDev = stateNumDev.second;
+
+            if (newState == currHashState) {
+                numDev ++;
+            } else if (newState == BluetoothProfile.STATE_CONNECTED ||
+                   (newState == BluetoothProfile.STATE_CONNECTING &&
+                    currHashState != BluetoothProfile.STATE_CONNECTED)) {
+                 numDev = 1;
+            } else if (numDev == 1 && oldState == currHashState) {
+                 update = true;
+            } else if (numDev > 1 && oldState == currHashState) {
+                 numDev --;
+
+                 if (currHashState == BluetoothProfile.STATE_CONNECTED ||
+                     currHashState == BluetoothProfile.STATE_CONNECTING) {
+                    newHashState = currHashState;
+                 }
+            } else {
+                 update = false;
+            }
+        }
+
+        if (update) {
+            mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
+                    numDev));
+        }
+    }
+
+    public synchronized void sendConnectionStateChange(BluetoothDevice
+            device, int profile, int state, int prevState) {
         // Since this is a binder call check if Bluetooth is on still
         if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
 
-        if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
-            if (!validateProfileConnectionState(state) ||
-                    !validateProfileConnectionState(prevState)) {
-                // Previously, an invalid state was broadcast anyway,
-                // with the invalid state converted to -1 in the intent.
-                // Better to log an error and not send an intent with
-                // invalid contents or set mAdapterConnectionState to -1.
-                Log.e(TAG, "Error in sendConnectionStateChange: "
-                        + "prevState " + prevState + " state " + state);
-                return;
-            }
+        if (!validateProfileConnectionState(state) ||
+                !validateProfileConnectionState(prevState)) {
+            // Previously, an invalid state was broadcast anyway,
+            // with the invalid state converted to -1 in the intent.
+            // Better to log an error and not send an intent with
+            // invalid contents or set mAdapterConnectionState to -1.
+            Log.e(TAG, "Error in sendConnectionStateChange: "
+                    + "prevState " + prevState + " state " + state);
+            return;
+        }
 
+        updateProfileConnectionState(profile, state, prevState);
+
+        if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
             mAdapterConnectionState = state;
 
             if (state == BluetoothProfile.STATE_DISCONNECTED) {
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 79ade260..d78bbbf 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -97,8 +97,18 @@
      * Refreshes the "searchables" list when packages are added/removed.
      */
     class MyPackageMonitor extends PackageMonitor {
+
         @Override
         public void onSomePackagesChanged() {
+            updateSearchables();
+        }
+
+        @Override
+        public void onPackageModified(String pkg) {
+            updateSearchables();
+        }
+
+        private void updateSearchables() {
             // Update list of searchable activities
             getSearchables().buildSearchableList();
             // Inform all listeners that the list of searchables has been updated.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c51ba2a..4c563ce 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -46,7 +46,6 @@
 import android.view.InputDevice;
 import android.view.InputHandler;
 import android.view.InputQueue;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
 import android.view.View;
@@ -54,8 +53,9 @@
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
-import android.view.WindowManagerPolicy;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -459,6 +459,44 @@
         public void onSurfaceDestroyed(SurfaceHolder holder) {
         }
         
+        protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
+            out.print(prefix); out.print("mInitializing="); out.print(mInitializing);
+                    out.print(" mDestroyed="); out.println(mDestroyed);
+            out.print(prefix); out.print("mVisible="); out.print(mVisible);
+                    out.print(" mScreenOn="); out.print(mScreenOn);
+                    out.print(" mReportedVisible="); out.println(mReportedVisible);
+            out.print(prefix); out.print("mCreated="); out.print(mCreated);
+                    out.print(" mSurfaceCreated="); out.print(mSurfaceCreated);
+                    out.print(" mIsCreating="); out.print(mIsCreating);
+                    out.print(" mDrawingAllowed="); out.println(mDrawingAllowed);
+            out.print(prefix); out.print("mWidth="); out.print(mWidth);
+                    out.print(" mCurWidth="); out.print(mCurWidth);
+                    out.print(" mHeight="); out.print(mHeight);
+                    out.print(" mCurHeight="); out.println(mCurHeight);
+            out.print(prefix); out.print("mType="); out.print(mType);
+                    out.print(" mWindowFlags="); out.print(mWindowFlags);
+                    out.print(" mCurWindowFlags="); out.println(mCurWindowFlags);
+            out.print(prefix); out.print("mVisibleInsets=");
+                    out.print(mVisibleInsets.toShortString());
+                    out.print(" mWinFrame="); out.print(mWinFrame.toShortString());
+                    out.print(" mContentInsets="); out.println(mContentInsets.toShortString());
+            out.print(prefix); out.print("mConfiguration="); out.println(mConfiguration);
+            out.print(prefix); out.print("mLayout="); out.println(mLayout);
+            synchronized (mLock) {
+                out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset);
+                        out.print(" mPendingXOffset="); out.println(mPendingXOffset);
+                out.print(prefix); out.print("mPendingXOffsetStep=");
+                        out.print(mPendingXOffsetStep);
+                        out.print(" mPendingXOffsetStep="); out.println(mPendingXOffsetStep);
+                out.print(prefix); out.print("mOffsetMessageEnqueued=");
+                        out.print(mOffsetMessageEnqueued);
+                        out.print(" mPendingSync="); out.println(mPendingSync);
+                if (mPendingMove != null) {
+                    out.print(prefix); out.print("mPendingMove="); out.println(mPendingMove);
+                }
+            }
+        }
+
         private void dispatchPointer(MotionEvent event) {
             if (event.isTouchEvent()) {
                 synchronized (mLock) {
@@ -1012,4 +1050,14 @@
      * is in the wallpaper picker viewing a preview of it as well.
      */
     public abstract Engine onCreateEngine();
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter out, String[] args) {
+        out.print("State of wallpaper "); out.print(this); out.println(":");
+        for (int i=0; i<mActiveEngines.size(); i++) {
+            Engine engine = mActiveEngines.get(i);
+            out.print("  Engine "); out.print(engine); out.println(":");
+            engine.dump("    ", fd, out, args);
+        }
+    }
 }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index b4e8ab4..a08ba2a 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -65,6 +65,7 @@
  *
  * {@link #onStop} tells the engine that it should stop all ongoing synthesis, if
  * any. Any pending data from the current synthesis will be discarded.
+ *
  */
 // TODO: Add a link to the sample TTS engine once it's done.
 public abstract class TextToSpeechService extends Service {
@@ -80,6 +81,7 @@
     // associated with this TTS engine. Will handle all requests except synthesis
     // to file requests, which occur on the synthesis thread.
     private AudioPlaybackHandler mAudioPlaybackHandler;
+    private TtsEngines mEngineHelper;
 
     private CallbackMap mCallbacks;
     private String mPackageName;
@@ -96,12 +98,15 @@
         mAudioPlaybackHandler = new AudioPlaybackHandler();
         mAudioPlaybackHandler.start();
 
+        mEngineHelper = new TtsEngines(this);
+
         mCallbacks = new CallbackMap();
 
         mPackageName = getApplicationInfo().packageName;
 
+        String[] defaultLocale = getSettingsLocale();
         // Load default language
-        onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
+        onLoadLanguage(defaultLocale[0], defaultLocale[1], defaultLocale[2]);
     }
 
     @Override
@@ -195,30 +200,15 @@
         return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE);
     }
 
-    private String getDefaultLanguage() {
-        return getSecureSettingString(Settings.Secure.TTS_DEFAULT_LANG,
-                Locale.getDefault().getISO3Language());
-    }
-
-    private String getDefaultCountry() {
-        return getSecureSettingString(Settings.Secure.TTS_DEFAULT_COUNTRY,
-                Locale.getDefault().getISO3Country());
-    }
-
-    private String getDefaultVariant() {
-        return getSecureSettingString(Settings.Secure.TTS_DEFAULT_VARIANT,
-                Locale.getDefault().getVariant());
+    private String[] getSettingsLocale() {
+        final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
+        return TtsEngines.parseLocalePref(locale);
     }
 
     private int getSecureSettingInt(String name, int defaultValue) {
         return Settings.Secure.getInt(getContentResolver(), name, defaultValue);
     }
 
-    private String getSecureSettingString(String name, String defaultValue) {
-        String value = Settings.Secure.getString(getContentResolver(), name);
-        return value != null ? value : defaultValue;
-    }
-
     /**
      * Synthesizer thread. This thread is used to run {@link SynthHandler}.
      */
@@ -458,6 +448,7 @@
     class SynthesisSpeechItem extends SpeechItem {
         private final String mText;
         private final SynthesisRequest mSynthesisRequest;
+        private final String[] mDefaultLocale;
         // Non null after synthesis has started, and all accesses
         // guarded by 'this'.
         private AbstractSynthesisCallback mSynthesisCallback;
@@ -467,6 +458,7 @@
             super(callingApp, params);
             mText = text;
             mSynthesisRequest = new SynthesisRequest(mText, mParams);
+            mDefaultLocale = getSettingsLocale();
             setRequestParams(mSynthesisRequest);
             mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName);
         }
@@ -523,7 +515,7 @@
         }
 
         public String getLanguage() {
-            return getStringParam(Engine.KEY_PARAM_LANGUAGE, getDefaultLanguage());
+            return getStringParam(Engine.KEY_PARAM_LANGUAGE, mDefaultLocale[0]);
         }
 
         private boolean hasLanguage() {
@@ -531,12 +523,12 @@
         }
 
         private String getCountry() {
-            if (!hasLanguage()) return getDefaultCountry();
+            if (!hasLanguage()) return mDefaultLocale[1];
             return getStringParam(Engine.KEY_PARAM_COUNTRY, "");
         }
 
         private String getVariant() {
-            if (!hasLanguage()) return getDefaultVariant();
+            if (!hasLanguage()) return mDefaultLocale[2];
             return getStringParam(Engine.KEY_PARAM_VARIANT, "");
         }
 
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 5f0cb74..bb72bea 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -17,6 +17,7 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -27,6 +28,8 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import static android.provider.Settings.Secure.getString;
+
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech.Engine;
 import android.speech.tts.TextToSpeech.EngineInfo;
@@ -40,6 +43,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Support class for querying the list of available engines
@@ -52,6 +56,9 @@
  */
 public class TtsEngines {
     private static final String TAG = "TtsEngines";
+    private static final boolean DBG = false;
+
+    private static final String LOCALE_DELIMITER = "-";
 
     private final Context mContext;
 
@@ -65,7 +72,7 @@
      *         the highest ranked engine is returned as per {@link EngineInfoComparator}.
      */
     public String getDefaultEngine() {
-        String engine = Settings.Secure.getString(mContext.getContentResolver(),
+        String engine = getString(mContext.getContentResolver(),
                 Settings.Secure.TTS_DEFAULT_SYNTH);
         return isEngineInstalled(engine) ? engine : getHighestRankedEngineName();
     }
@@ -129,12 +136,6 @@
         return engines;
     }
 
-    // TODO: Used only by the settings app. Remove once
-    // the settings UI change has been finalized.
-    public boolean isEngineEnabled(String engine) {
-        return isEngineInstalled(engine);
-    }
-
     private boolean isSystemEngine(ServiceInfo info) {
         final ApplicationInfo appInfo = info.applicationInfo;
         return appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
@@ -182,7 +183,7 @@
      * The name of the XML tag that text to speech engines must use to
      * declare their meta data.
      *
-     * {@link com.android.internal.R.styleable.TextToSpeechEngine}
+     * {@link com.android.internal.R.styleable#TextToSpeechEngine}
      */
     private static final String XML_TAG_NAME = "tts-engine";
 
@@ -279,4 +280,175 @@
         }
     }
 
+    /**
+     * Returns the locale string for a given TTS engine. Attempts to read the
+     * value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
+     * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
+     * both these values are empty, the default phone locale is returned.
+     *
+     * @param engineName the engine to return the locale for.
+     * @return the locale string preference for this engine. Will be non null
+     *         and non empty.
+     */
+    public String getLocalePrefForEngine(String engineName) {
+        String locale = parseEnginePrefFromList(
+                getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
+                engineName);
+
+        if (TextUtils.isEmpty(locale)) {
+            // The new style setting is unset, attempt to return the old style setting.
+            locale = getV1Locale();
+        }
+
+        if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale);
+
+        return locale;
+    }
+
+    /**
+     * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
+     * Varies from {@link String#split} in that it will always return an array
+     * of length 3 with non null values.
+     */
+    public static String[] parseLocalePref(String pref) {
+        String[] returnVal = new String[] { "", "", ""};
+        if (!TextUtils.isEmpty(pref)) {
+            String[] split = pref.split(LOCALE_DELIMITER);
+            System.arraycopy(split, 0, returnVal, 0, split.length);
+        }
+
+        if (DBG) Log.d(TAG, "parseLocalePref(" + returnVal[0] + "," + returnVal[1] +
+                "," + returnVal[2] +")");
+
+        return returnVal;
+    }
+
+    /**
+     * @return the old style locale string constructed from
+     *         {@link Settings.Secure#TTS_DEFAULT_LANG},
+     *         {@link Settings.Secure#TTS_DEFAULT_COUNTRY} and
+     *         {@link Settings.Secure#TTS_DEFAULT_VARIANT}. If no such locale is set,
+     *         then return the default phone locale.
+     */
+    private String getV1Locale() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        final String lang = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_LANG);
+        final String country = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_COUNTRY);
+        final String variant = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_VARIANT);
+
+        if (TextUtils.isEmpty(lang)) {
+            return getDefaultLocale();
+        }
+
+        String v1Locale = lang;
+        if (!TextUtils.isEmpty(country)) {
+            v1Locale += LOCALE_DELIMITER + country;
+        }
+        if (!TextUtils.isEmpty(variant)) {
+            v1Locale += LOCALE_DELIMITER + variant;
+        }
+
+        return v1Locale;
+    }
+
+    private String getDefaultLocale() {
+        final Locale locale = Locale.getDefault();
+
+        return locale.getISO3Language() + LOCALE_DELIMITER + locale.getISO3Country() +
+                LOCALE_DELIMITER + locale.getVariant();
+    }
+
+    /**
+     * Parses a comma separated list of engine locale preferences. The list is of the
+     * form {@code "engine_name_1:locale_1,engine_name_2:locale2"} and so on and
+     * so forth. Returns null if the list is empty, malformed or if there is no engine
+     * specific preference in the list.
+     */
+    private static String parseEnginePrefFromList(String prefValue, String engineName) {
+        if (TextUtils.isEmpty(prefValue)) {
+            return null;
+        }
+
+        String[] prefValues = prefValue.split(",");
+
+        for (String value : prefValues) {
+            final int delimiter = value.indexOf(':');
+            if (delimiter > 0) {
+                if (engineName.equals(value.substring(0, delimiter))) {
+                    return value.substring(delimiter + 1);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public synchronized void updateLocalePrefForEngine(String name, String newLocale) {
+        final String prefList = Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.TTS_DEFAULT_LOCALE);
+        if (DBG) {
+            Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale +
+                    "), originally: " + prefList);
+        }
+
+        final String newPrefList = updateValueInCommaSeparatedList(prefList,
+                name, newLocale);
+
+        if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString());
+
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.TTS_DEFAULT_LOCALE, newPrefList.toString());
+    }
+
+    /**
+     * Updates the value for a given key in a comma separated list of key value pairs,
+     * each of which are delimited by a colon. If no value exists for the given key,
+     * the kay value pair are appended to the end of the list.
+     */
+    private String updateValueInCommaSeparatedList(String list, String key,
+            String newValue) {
+        StringBuilder newPrefList = new StringBuilder();
+        if (TextUtils.isEmpty(list)) {
+            // If empty, create a new list with a single entry.
+            newPrefList.append(key).append(':').append(newValue);
+        } else {
+            String[] prefValues = list.split(",");
+            // Whether this is the first iteration in the loop.
+            boolean first = true;
+            // Whether we found the given key.
+            boolean found = false;
+            for (String value : prefValues) {
+                final int delimiter = value.indexOf(':');
+                if (delimiter > 0) {
+                    if (key.equals(value.substring(0, delimiter))) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            newPrefList.append(',');
+                        }
+                        found = true;
+                        newPrefList.append(key).append(':').append(newValue);
+                    } else {
+                        if (first) {
+                            first = false;
+                        } else {
+                            newPrefList.append(',');
+                        }
+                        // Copy across the entire key + value as is.
+                        newPrefList.append(value);
+                    }
+                }
+            }
+
+            if (!found) {
+                // Not found, but the rest of the keys would have been copied
+                // over already, so just append it to the end.
+                newPrefList.append(',');
+                newPrefList.append(key).append(':').append(newValue);
+            }
+        }
+
+        return newPrefList.toString();
+    }
 }
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index 5ed2df4..6debc6b 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -50,22 +50,6 @@
         new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
 
     /**
-     * If the text contains any strong left to right non-format character, determines
-     * that the direction is left to right, falling back to left to right if it
-     * finds none.
-     */
-    public static final TextDirectionHeuristic ANYLTR_LTR =
-        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_LTR, false);
-
-    /**
-     * If the text contains any strong left to right non-format character, determines
-     * that the direction is left to right, falling back to right to left if it
-     * finds none.
-     */
-    public static final TextDirectionHeuristic ANYLTR_RTL =
-        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_LTR, true);
-
-    /**
      * If the text contains any strong right to left non-format character, determines
      * that the direction is right to left, falling back to left to right if it
      * finds none.
@@ -74,14 +58,6 @@
         new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
 
     /**
-     * If the text contains any strong right to left non-format character, determines
-     * that the direction is right to left, falling back to right to left if it
-     * finds none.
-     */
-    public static final TextDirectionHeuristic ANYRTL_RTL =
-        new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, true);
-
-    /**
      * Examines only the strong directional non-format characters, and if either
      * left to right or right to left characters are 60% or more of this total,
      * determines that the direction follows the majority of characters.  Falls
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 7a96a50..5e7e509 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -163,7 +163,9 @@
      * It is an error to lock a Blur surface, since it doesn't have
      * a backing store.
      * @hide
+     * @deprecated
      */
+    @Deprecated
     public static final int FX_SURFACE_BLUR     = 0x00010000;
     
     /** Creates a Dim surface. Everything behind this surface is dimmed
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index abd9ad6..17e637c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8087,6 +8087,11 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
+        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null) {
+            // Noop for views which are not visible and which are not running an animation. They
+            // will not get drawn and they should not set dirty flags as if they will be drawn
+            return;
+        }
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
                 (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
                 (mPrivateFlags & INVALIDATED) != INVALIDATED) {
@@ -8130,6 +8135,11 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
+        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null) {
+            // Noop for views which are not visible and which are not running an animation. They
+            // will not get drawn and they should not set dirty flags as if they will be drawn
+            return;
+        }
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
                 (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
                 (mPrivateFlags & INVALIDATED) != INVALIDATED) {
@@ -8182,6 +8192,11 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
         }
 
+        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null) {
+            // Noop for views which are not visible and which are not running an animation. They
+            // will not get drawn and they should not set dirty flags as if they will be drawn
+            return;
+        }
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
                 (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
                 (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
@@ -8217,6 +8232,11 @@
      * @hide
      */
     public void fastInvalidate() {
+        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null) {
+            // Noop for views which are not visible and which are not running an animation. They
+            // will not get drawn and they should not set dirty flags as if they will be drawn
+            return;
+        }
         if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
             (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
             (mPrivateFlags & INVALIDATED) != INVALIDATED) {
@@ -9165,7 +9185,8 @@
             mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
         }
         jumpDrawablesToCurrentState();
-        // Order is important here: LayoutDirection should be resolved before Padding and TextDirection
+        // Order is important here: LayoutDirection MUST be resolved before Padding
+        // and TextDirection
         resolveLayoutDirectionIfNeeded();
         resolvePadding();
         resolveTextDirection();
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index e1aa9a4..fb87e23 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -259,8 +259,9 @@
         mStreamControls = new HashMap<Integer,StreamControl>(STREAM_TYPES.length);
         Resources res = mContext.getResources();
         for (int i = 0; i < STREAM_TYPES.length; i++) {
+            final int streamType = STREAM_TYPES[i];
             StreamControl sc = new StreamControl();
-            sc.streamType = STREAM_TYPES[i];
+            sc.streamType = streamType;
             sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
             sc.group.setTag(sc);
             sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
@@ -273,10 +274,12 @@
             sc.iconMuteRes = STREAM_ICONS_MUTED[i];
             sc.icon.setImageResource(sc.iconRes);
             sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
-            sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(STREAM_TYPES[i]));
+            int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
+                    streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
+            sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(streamType) + plusOne);
             sc.seekbarView.setOnSeekBarChangeListener(this);
             sc.seekbarView.setTag(sc);
-            mStreamControls.put(STREAM_TYPES[i], sc);
+            mStreamControls.put(streamType, sc);
         }
     }
 
@@ -476,6 +479,9 @@
 
         StreamControl sc = mStreamControls.get(streamType);
         if (sc != null) {
+            if (sc.seekbarView.getMax() != max) {
+                sc.seekbarView.setMax(max);
+            }
             sc.seekbarView.setProgress(index);
         }
 
@@ -557,28 +563,6 @@
         }
     }
 
-//    /**
-//     * Makes the ringer icon visible with an icon that is chosen
-//     * based on the current ringer mode.
-//     */
-//    private void setRingerIcon() {
-//        mSmallStreamIcon.setVisibility(View.GONE);
-//        mLargeStreamIcon.setVisibility(View.VISIBLE);
-//
-//        int ringerMode = mAudioService.getRingerMode();
-//        int icon;
-//
-//        if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
-//
-//        if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
-//            icon = com.android.internal.R.drawable.ic_volume_off;
-//        } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-//            icon = com.android.internal.R.drawable.ic_vibrate;
-//        } else {
-//            icon = com.android.internal.R.drawable.ic_volume;
-//        }
-//        mLargeStreamIcon.setImageResource(icon);
-//    }
 
     /**
      * Switch between icons because Bluetooth music is same as music volume, but with
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e0e1a1a..75c7592 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -127,6 +127,7 @@
     private int mLocalFeatures = DEFAULT_FEATURES;
 
     private boolean mHaveWindowFormat = false;
+    private boolean mHaveDimAmount = false;
     private int mDefaultWindowFormat = PixelFormat.OPAQUE;
 
     private boolean mHasSoftInputMode = false;
@@ -745,6 +746,23 @@
     }
 
     /**
+     * Set the amount of dim behind the window when using
+     * {@link WindowManager.LayoutParams#FLAG_DIM_BEHIND}.  This overrides
+     * the default dim amount of that is selected by the Window based on
+     * its theme.
+     *
+     * @param amount The new dim amount, from 0 for no dim to 1 for full dim.
+     */
+    public void setDimAmount(float amount) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.dimAmount = amount;
+        mHaveDimAmount = true;
+        if (mCallback != null) {
+            mCallback.onWindowAttributesChanged(attrs);
+        }
+    }
+
+    /**
      * Specify custom window attributes.  <strong>PLEASE NOTE:</strong> the
      * layout params you give here should generally be from values previously
      * retrieved with {@link #getAttributes()}; you probably do not want to
@@ -1193,6 +1211,11 @@
         }
     }
 
+    /** @hide */
+    protected boolean haveDimAmount() {
+        return mHaveDimAmount;
+    }
+
     public abstract void setChildDrawable(int featureId, Drawable drawable);
 
     public abstract void setChildInt(int featureId, int value);
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 8a30c7b..1b4edf1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -871,6 +871,16 @@
     public void systemReady();
 
     /**
+     * Show boot time message to the user.
+     */
+    public void showBootMessage(final CharSequence msg, final boolean always);
+
+    /**
+     * Hide the UI for showing boot messages, never to be displayed again.
+     */
+    public void hideBootMessages();
+
+    /**
      * Called when userActivity is signalled in the power manager.
      * This is safe to call from any thread, with any window manager locks held or not.
      */
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index dae118e..86f061a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -54,6 +54,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -2788,7 +2789,10 @@
             reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
             // Time to start stealing events! Once we've stolen them, don't let anyone
             // steal from us
-            requestDisallowInterceptTouchEvent(true);
+            final ViewParent parent = getParent();
+            if (parent != null) {
+                parent.requestDisallowInterceptTouchEvent(true);
+            }
             return true;
         }
 
@@ -2848,9 +2852,7 @@
         View v;
         int deltaY;
 
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
+        initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
 
         switch (action & MotionEvent.ACTION_MASK) {
@@ -2955,7 +2957,10 @@
                     // Make sure that we do so in case we're in a parent that can intercept.
                     if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0 &&
                             Math.abs(deltaY) > mTouchSlop) {
-                        requestDisallowInterceptTouchEvent(true);
+                        final ViewParent parent = getParent();
+                        if (parent != null) {
+                            parent.requestDisallowInterceptTouchEvent(true);
+                        }
                     }
 
                     final int rawDeltaY = deltaY;
@@ -2998,7 +3003,9 @@
                                     0, mOverscrollDistance, true);
                             if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
                                 // Don't allow overfling if we're at the edge.
-                                mVelocityTracker.clear();
+                                if (mVelocityTracker != null) {
+                                    mVelocityTracker.clear();
+                                }
                             }
 
                             final int overscrollMode = getOverScrollMode();
@@ -3259,10 +3266,7 @@
                 handler.removeCallbacks(mPendingCheckForLongPress);
             }
 
-            if (mVelocityTracker != null) {
-                mVelocityTracker.recycle();
-                mVelocityTracker = null;
-            }
+            recycleVelocityTracker();
 
             mActivePointerId = INVALID_POINTER;
 
@@ -3307,10 +3311,7 @@
                     handler.removeCallbacks(mPendingCheckForLongPress);
                 }
 
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
+                recycleVelocityTracker();
             }
 
             if (mEdgeGlowTop != null) {
@@ -3450,6 +3451,35 @@
         mGlowPaddingRight = rightPadding;
     }
 
+    private void initOrResetVelocityTracker() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+    }
+
+    private void initVelocityTrackerIfNotExists() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+    }
+
+    private void recycleVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        if (disallowIntercept) {
+            recycleVelocityTracker();
+        }
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
@@ -3487,6 +3517,8 @@
                 clearScrollingCache();
             }
             mLastY = Integer.MIN_VALUE;
+            initOrResetVelocityTracker();
+            mVelocityTracker.addMovement(ev);
             if (touchMode == TOUCH_MODE_FLING) {
                 return true;
             }
@@ -3502,6 +3534,8 @@
                     mActivePointerId = ev.getPointerId(pointerIndex);
                 }
                 final int y = (int) ev.getY(pointerIndex);
+                initVelocityTrackerIfNotExists();
+                mVelocityTracker.addMovement(ev);
                 if (startScrollIfNeeded(y - mMotionY)) {
                     return true;
                 }
@@ -3510,9 +3544,11 @@
             break;
         }
 
+        case MotionEvent.ACTION_CANCEL:
         case MotionEvent.ACTION_UP: {
             mTouchMode = TOUCH_MODE_REST;
             mActivePointerId = INVALID_POINTER;
+            recycleVelocityTracker();
             reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
             break;
         }
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index b428301..d638732 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -399,6 +399,35 @@
         return false;
     }
 
+    private void initOrResetVelocityTracker() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+    }
+
+    private void initVelocityTrackerIfNotExists() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+    }
+
+    private void recycleVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        if (disallowIntercept) {
+            recycleVelocityTracker();
+        }
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         /*
@@ -440,6 +469,8 @@
                 if (xDiff > mTouchSlop) {
                     mIsBeingDragged = true;
                     mLastMotionX = x;
+                    initVelocityTrackerIfNotExists();
+                    mVelocityTracker.addMovement(ev);
                     if (mParent != null) mParent.requestDisallowInterceptTouchEvent(true);
                 }
                 break;
@@ -449,6 +480,7 @@
                 final float x = ev.getX();
                 if (!inChild((int) x, (int) ev.getY())) {
                     mIsBeingDragged = false;
+                    recycleVelocityTracker();
                     break;
                 }
 
@@ -459,6 +491,9 @@
                 mLastMotionX = x;
                 mActivePointerId = ev.getPointerId(0);
 
+                initOrResetVelocityTracker();
+                mVelocityTracker.addMovement(ev);
+
                 /*
                 * If being flinged and user touches the screen, initiate drag;
                 * otherwise don't.  mScroller.isFinished should be false when
@@ -498,9 +533,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
+        initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
 
         final int action = ev.getAction();
@@ -584,11 +617,8 @@
 
                     mActivePointerId = INVALID_POINTER;
                     mIsBeingDragged = false;
+                    recycleVelocityTracker();
 
-                    if (mVelocityTracker != null) {
-                        mVelocityTracker.recycle();
-                        mVelocityTracker = null;
-                    }
                     if (mEdgeGlowLeft != null) {
                         mEdgeGlowLeft.onRelease();
                         mEdgeGlowRight.onRelease();
@@ -602,10 +632,8 @@
                     }
                     mActivePointerId = INVALID_POINTER;
                     mIsBeingDragged = false;
-                    if (mVelocityTracker != null) {
-                        mVelocityTracker.recycle();
-                        mVelocityTracker = null;
-                    }
+                    recycleVelocityTracker();
+
                     if (mEdgeGlowLeft != null) {
                         mEdgeGlowLeft.onRelease();
                         mEdgeGlowRight.onRelease();
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index e59f731..09c875b 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -408,6 +408,36 @@
         return false;
     }
 
+    private void initOrResetVelocityTracker() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+    }
+
+    private void initVelocityTrackerIfNotExists() {
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+    }
+
+    private void recycleVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        if (disallowIntercept) {
+            recycleVelocityTracker();
+        }
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+    }
+
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         /*
@@ -449,6 +479,8 @@
                 if (yDiff > mTouchSlop) {
                     mIsBeingDragged = true;
                     mLastMotionY = y;
+                    initVelocityTrackerIfNotExists();
+                    mVelocityTracker.addMovement(ev);
                     if (mScrollStrictSpan == null) {
                         mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
                     }
@@ -460,6 +492,7 @@
                 final float y = ev.getY();
                 if (!inChild((int) ev.getX(), (int) y)) {
                     mIsBeingDragged = false;
+                    recycleVelocityTracker();
                     break;
                 }
 
@@ -470,6 +503,8 @@
                 mLastMotionY = y;
                 mActivePointerId = ev.getPointerId(0);
 
+                initOrResetVelocityTracker();
+                mVelocityTracker.addMovement(ev);
                 /*
                 * If being flinged and user touches the screen, initiate drag;
                 * otherwise don't.  mScroller.isFinished should be false when
@@ -487,6 +522,7 @@
                 /* Release the drag */
                 mIsBeingDragged = false;
                 mActivePointerId = INVALID_POINTER;
+                recycleVelocityTracker();
                 if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
                     invalidate();
                 }
@@ -505,9 +541,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
+        initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
 
         final int action = ev.getAction();
@@ -1441,10 +1475,7 @@
     private void endDrag() {
         mIsBeingDragged = false;
 
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
+        recycleVelocityTracker();
 
         if (mEdgeGlowTop != null) {
             mEdgeGlowTop.onRelease();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7a5a091..662b964 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10745,8 +10745,7 @@
                         TextDirectionHeuristics.FIRSTSTRONG_LTR);
                 break;
             case TEXT_DIRECTION_ANY_RTL:
-                mTextDir = (defaultIsRtl ? TextDirectionHeuristics.ANYRTL_RTL:
-                        TextDirectionHeuristics.ANYRTL_LTR);
+                mTextDir = TextDirectionHeuristics.ANYRTL_LTR;
                 break;
             case TEXT_DIRECTION_CHAR_COUNT:
                 mTextDir = (defaultIsRtl ? TextDirectionHeuristics.CHARCOUNT_RTL:
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index d1c3e64..daabf42 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -122,10 +122,6 @@
             closer.dialog = dialog;
             dialog.setOnDismissListener(closer);
             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            if (!context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_sf_slowBlur)) {
-                dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-            }
             dialog.show();
         } else {
             beginShutdownSequence(context);
@@ -185,10 +181,6 @@
         pd.setIndeterminate(true);
         pd.setCancelable(false);
         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        if (!context.getResources().getBoolean(
-                com.android.internal.R.bool.config_sf_slowBlur)) {
-            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-        }
 
         pd.show();
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index df4243a..246c4de 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -252,7 +252,7 @@
      * @return true if the overflow menu was shown, false otherwise.
      */
     public boolean showOverflowMenu() {
-        if (mReserveOverflow && !isOverflowMenuShowing() && mMenuView != null &&
+        if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
                 mPostedOpenRunnable == null) {
             OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
             mPostedOpenRunnable = new OpenOverflowRunnable(popup);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 5622b44..c30e83b 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -1057,9 +1057,8 @@
                     mNonActionItems.add(item);
                 }
             }
-        } else if (mActionItems.size() + mNonActionItems.size() != getVisibleItems().size()) {
-            // Nobody flagged anything, but if something doesn't add up then treat everything
-            // as non-action items.
+        } else {
+            // Nobody flagged anything, everything is a non-action item.
             // (This happens during a first pass with no action-item presenters.)
             mActionItems.clear();
             mNonActionItems.clear();
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 28181ba..4efb29f 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -550,10 +550,9 @@
 
             if (mTitleLayout != null && (flagsChanged &
                     (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
-                final boolean homeAsUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-                final boolean titleUp = homeAsUp && !showHome;
-                mTitleUpView.setVisibility(titleUp ? VISIBLE : GONE);
-                mTitleLayout.setEnabled(titleUp);
+                final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
+                mTitleLayout.setEnabled(!showHome && homeAsUp);
             }
 
             if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
@@ -730,10 +729,9 @@
             }
 
             final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-            final boolean titleUp = homeAsUp &&
-                    (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) == 0;
-            mTitleUpView.setVisibility(titleUp ? VISIBLE : GONE);
-            mTitleLayout.setEnabled(titleUp);
+            final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
+            mTitleLayout.setEnabled(homeAsUp && !showHome);
         }
 
         addView(mTitleLayout);
@@ -805,7 +803,7 @@
         int leftOfCenter = availableWidth / 2;
         int rightOfCenter = leftOfCenter;
 
-        View homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
+        HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
 
         if (homeLayout.getVisibility() != GONE) {
             final LayoutParams lp = homeLayout.getLayoutParams();
@@ -817,7 +815,7 @@
             }
             homeLayout.measure(homeWidthSpec,
                     MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-            final int homeWidth = homeLayout.getMeasuredWidth();
+            final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset();
             availableWidth = Math.max(0, availableWidth - homeWidth);
             leftOfCenter = Math.max(0, availableWidth - homeWidth);
         }
@@ -962,9 +960,10 @@
             return;
         }
 
-        View homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
+        HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
         if (homeLayout.getVisibility() != GONE) {
-            x += positionChild(homeLayout, x, y, contentHeight);
+            final int leftOffset = homeLayout.getLeftOffset();
+            x += positionChild(homeLayout, x + leftOffset, y, contentHeight) + leftOffset;
         }
 
         if (mExpandedActionView == null) {
@@ -1171,6 +1170,7 @@
     private static class HomeView extends FrameLayout {
         private View mUpView;
         private ImageView mIconView;
+        private int mUpWidth;
 
         public HomeView(Context context) {
             this(context, null);
@@ -1194,15 +1194,16 @@
             mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
         }
 
-        public int getVerticalIconPadding() {
-            return mIconView.getPaddingTop() + mIconView.getPaddingBottom();
+        public int getLeftOffset() {
+            return mUpView.getVisibility() == GONE ? mUpWidth : 0;
         }
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
             final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
-            int width = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+            mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+            int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth;
             int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
             measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
             final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png
index 61ea2b0..83b2bce 100644
--- a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png
index 83b2bce..61ea2b0 100644
--- a/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png
index c03e658..19b153b 100644
--- a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png
index 19b153b..c03e658 100644
--- a/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png
index d69b772..a210f3c 100644
--- a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png
index a210f3c..d69b772 100644
--- a/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/popup_inline_error_above_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/activity_list_item.xml b/core/res/res/layout/activity_list_item.xml
index 25d95fd..7022fe1 100644
--- a/core/res/res/layout/activity_list_item.xml
+++ b/core/res/res/layout/activity_list_item.xml
@@ -22,8 +22,8 @@
     android:layout_height="wrap_content"
     android:paddingTop="1dip"
     android:paddingBottom="1dip"
-    android:paddingLeft="6dip"
-    android:paddingRight="6dip">
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip">
 
     <ImageView android:id="@+id/icon"
         android:layout_width="24dip"
diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml
index 60bc24c..a3e4961 100644
--- a/core/res/res/layout/input_method_extract_view.xml
+++ b/core/res/res/layout/input_method_extract_view.xml
@@ -40,7 +40,6 @@
             android:layout_height="match_parent"
             android:paddingLeft="8dip"
             android:paddingRight="8dip"
-            android:background="@android:drawable/keyboard_accessory_bg_landscape"
         >
         
         <android.inputmethodservice.ExtractButton android:id="@+id/inputExtractAction"
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index aaff4c7..93bd76b 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -26,8 +26,8 @@
         android:layout_weight="1"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginLeft="6dip"
-        android:layout_marginRight="6dip"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
         android:duplicateParentState="true">
         
         <TextView 
@@ -36,7 +36,7 @@
             android:layout_height="wrap_content"
             android:layout_alignParentTop="true"
             android:layout_alignParentLeft="true"
-            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textAppearance="?android:attr/textAppearanceListItemSmall"
             android:singleLine="true"
             android:duplicateParentState="true"
             android:ellipsize="marquee"
diff --git a/core/res/res/layout/select_dialog_item_holo.xml b/core/res/res/layout/select_dialog_item_holo.xml
index 0c700cf..3d19c06 100644
--- a/core/res/res/layout/select_dialog_item_holo.xml
+++ b/core/res/res/layout/select_dialog_item_holo.xml
@@ -27,7 +27,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:textColor="?android:attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
     android:paddingLeft="16dip"
diff --git a/core/res/res/layout/simple_expandable_list_item_1.xml b/core/res/res/layout/simple_expandable_list_item_1.xml
index dc3e58e..df4324b 100644
--- a/core/res/res/layout/simple_expandable_list_item_1.xml
+++ b/core/res/res/layout/simple_expandable_list_item_1.xml
@@ -19,6 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
     android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
 />
diff --git a/core/res/res/layout/simple_expandable_list_item_2.xml b/core/res/res/layout/simple_expandable_list_item_2.xml
index b48b444..c0935fa 100644
--- a/core/res/res/layout/simple_expandable_list_item_2.xml
+++ b/core/res/res/layout/simple_expandable_list_item_2.xml
@@ -27,7 +27,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="6dip"
-        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textAppearance="?android:attr/textAppearanceListItem"
     />
 
     <TextView android:id="@android:id/text2"
diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml
index c9c77a5..252e006 100644
--- a/core/res/res/layout/simple_list_item_1.xml
+++ b/core/res/res/layout/simple_list_item_1.xml
@@ -18,8 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
-    android:paddingLeft="6dip"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
     android:minHeight="?android:attr/listPreferredItemHeight"
 />
diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml
index c87922c..9b6c62a 100644
--- a/core/res/res/layout/simple_list_item_2.xml
+++ b/core/res/res/layout/simple_list_item_2.xml
@@ -24,9 +24,9 @@
 	<TextView android:id="@android:id/text1"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-        android:layout_marginLeft="6dip"
-        android:layout_marginTop="6dip"
-		android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_marginLeft="8dip"
+        android:layout_marginTop="8dip"
+		android:textAppearance="?android:attr/textAppearanceListItem"
 	/>
 		
 	<TextView android:id="@android:id/text2"
diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml
index 8416df2..d60f93b 100644
--- a/core/res/res/layout/simple_list_item_activated_1.xml
+++ b/core/res/res/layout/simple_list_item_activated_1.xml
@@ -18,7 +18,7 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:minHeight="?android:attr/listPreferredItemHeight"
diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml
index 2ffbf02..5be5c92 100644
--- a/core/res/res/layout/simple_list_item_activated_2.xml
+++ b/core/res/res/layout/simple_list_item_activated_2.xml
@@ -27,8 +27,8 @@
     <TextView android:id="@android:id/text1"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="6dip"
-        android:layout_marginTop="6dip"
+        android:layout_marginLeft="8dip"
+        android:layout_marginTop="8dip"
         android:textAppearance="?android:attr/textAppearanceLarge"
     />
 
diff --git a/core/res/res/layout/simple_list_item_checked.xml b/core/res/res/layout/simple_list_item_checked.xml
index 5f99044..79d3a18 100644
--- a/core/res/res/layout/simple_list_item_checked.xml
+++ b/core/res/res/layout/simple_list_item_checked.xml
@@ -18,9 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
     android:checkMark="?android:attr/textCheckMark"
-    android:paddingLeft="6dip"
-    android:paddingRight="6dip"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
 />
diff --git a/core/res/res/layout/simple_list_item_multiple_choice.xml b/core/res/res/layout/simple_list_item_multiple_choice.xml
index 05c66f3..0305427 100644
--- a/core/res/res/layout/simple_list_item_multiple_choice.xml
+++ b/core/res/res/layout/simple_list_item_multiple_choice.xml
@@ -18,9 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
     android:checkMark="?android:attr/listChoiceIndicatorMultiple"
-    android:paddingLeft="6dip"
-    android:paddingRight="6dip"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
 />
diff --git a/core/res/res/layout/simple_list_item_single_choice.xml b/core/res/res/layout/simple_list_item_single_choice.xml
index 27afd1d..ac4a4a8 100644
--- a/core/res/res/layout/simple_list_item_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_single_choice.xml
@@ -18,9 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
     android:checkMark="?android:attr/listChoiceIndicatorSingle"
-    android:paddingLeft="6dip"
-    android:paddingRight="6dip"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
 />
diff --git a/core/res/res/layout/simple_selectable_list_item.xml b/core/res/res/layout/simple_selectable_list_item.xml
index 518bcd0..6ce22d6 100644
--- a/core/res/res/layout/simple_selectable_list_item.xml
+++ b/core/res/res/layout/simple_selectable_list_item.xml
@@ -18,9 +18,9 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
     android:background="?android:attr/listChoiceBackgroundIndicator"
-    android:paddingLeft="6dip"
-    android:paddingRight="9dip"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
 />
diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml
index a453ac1..2097049 100644
--- a/core/res/res/values-sw600dp/bools.xml
+++ b/core/res/res/values-sw600dp/bools.xml
@@ -18,4 +18,5 @@
     <bool name="preferences_prefer_dual_pane">true</bool>
     <bool name="show_ongoing_ime_switcher">false</bool>
     <bool name="action_bar_expanded_action_views_exclusive">false</bool>
+    <bool name="target_honeycomb_needs_options_menu">false</bool>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index aa3397f..8db6b4f 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -236,6 +236,11 @@
         <!-- The list item height for search results. @hide -->
         <attr name="searchResultListItemHeight" format="dimension" />
 
+        <!-- The preferred TextAppearance for the primary text of list items. -->
+        <attr name="textAppearanceListItem" format="reference" />
+        <!-- The preferred TextAppearance for the primary text of small list items. -->
+        <attr name="textAppearanceListItemSmall" format="reference" />
+
         <!-- The drawable for the list divider. -->
         <attr name="listDivider" format="reference" />
         <!-- The list divider used in alert dialogs. -->
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 6e4db5e..87a98e2 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -20,4 +20,5 @@
     <bool name="preferences_prefer_dual_pane">false</bool>
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="action_bar_expanded_action_views_exclusive">true</bool>
+    <bool name="target_honeycomb_needs_options_menu">true</bool>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 74989e6..8fbb09e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -57,8 +57,9 @@
 
     <!-- Flag indicating whether the surface flinger is inefficient
          at performing a blur.  Used by parts of the UI to turn off
-         the blur effect where it isn't worth the performance hit. -->
-    <bool name="config_sf_slowBlur">false</bool>
+         the blur effect where it isn't worth the performance hit.
+         As of Honeycomb, blurring is not supported anymore. -->
+    <bool name="config_sf_slowBlur">true</bool>
 
     <!-- The duration (in milliseconds) of a short animation. -->
     <integer name="config_shortAnimTime">200</integer>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 730d971..a6bf1e0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1792,6 +1792,9 @@
   <public type="attr" name="actionBarItemBackground" />
   <public type="attr" name="actionModeSplitBackground" />
 
+  <public type="attr" name="textAppearanceListItem" />
+  <public type="attr" name="textAppearanceListItemSmall" />
+
   <public type="style" name="TextAppearance.SuggestionHighlight" />
 
   <public type="style" name="Theme.Holo.Light.DarkActionBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 27fa8d4..c80923d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2571,6 +2571,20 @@
     <string name="smv_process">The process <xliff:g id="process">%1$s</xliff:g> has
       has violated its self-enforced StrictMode policy.</string>
 
+    <!-- [CHAR LIMIT=40] Title of dialog that is shown when performing a system upgrade. -->
+    <string name="android_upgrading_title">Android is upgrading...</string>
+
+    <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk that is optimized. -->
+    <string name="android_upgrading_apk">Optimizing application
+        <xliff:g id="number" example="123">%1$d</xliff:g> of
+        <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+
+    <!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when reached the point of starting apps. -->
+    <string name="android_upgrading_starting_apps">Starting applications.</string>
+
+    <!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when the bulk of the upgrade work is done. -->
+    <string name="android_upgrading_complete">Finishing boot.</string>
+
     <!-- Notification text to tell the user that a heavy-weight application is running. -->
     <string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
 
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 786cdb5..903fc04 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -122,6 +122,8 @@
         <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeight</item>
         <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeight</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
+        <item name="textAppearanceListItem">?android:attr/textAppearanceLarge</item>
+        <item name="textAppearanceListItemSmall">?android:attr/textAppearanceLarge</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -715,9 +717,9 @@
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
          and a few custom attributes. -->
-    <style name="Theme.Holo.InputMethod" parent="Theme.Holo.Panel">
+    <style name="Theme.Holo.InputMethod" parent="Theme.Holo.Light.Panel">
         <item name="android:windowAnimationStyle">@android:style/Animation.InputMethod</item>
-        <item name="android:imeFullscreenBackground">@android:drawable/input_method_fullscreen_background_holo</item>
+        <item name="android:imeFullscreenBackground">@android:drawable/screen_background_selector_light</item>
         <item name="android:imeExtractEnterAnimation">@android:anim/input_method_extract_enter</item>
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
@@ -920,6 +922,7 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
+        <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -1222,6 +1225,7 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
+        <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 0af0177..5298125 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -162,7 +162,7 @@
         // TODO: Use an LRU
         while (mSize + size > mMaxSize) {
             size_t position = 0;
-#if LAYER_REMOVE_BIGGEST
+#if LAYER_REMOVE_BIGGEST_FIRST
             position = mCache.size() - 1;
 #endif
             Layer* victim = mCache.itemAt(position).mLayer;
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 63bb824..c14c9ca 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -19,6 +19,7 @@
 
 #include "Debug.h"
 #include "Layer.h"
+#include "Properties.h"
 #include "utils/SortedList.h"
 
 namespace android {
@@ -28,11 +29,6 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-// Indicates whether to remove the biggest layers first, or the smaller ones
-#define LAYER_REMOVE_BIGGEST 0
-// Textures used by layers must have dimensions multiples of this number
-#define LAYER_SIZE 64
-
 // Debug
 #if DEBUG_LAYERS
     #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a0f806a..e89d6ec 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1476,10 +1476,10 @@
     const float width = texture->width;
     const float height = texture->height;
 
-    const float u1 = (srcLeft + 0.5f) / width;
-    const float v1 = (srcTop + 0.5f)  / height;
-    const float u2 = (srcRight - 0.5f) / width;
-    const float v2 = (srcBottom - 0.5f) / height;
+    const float u1 = fmax(0.0f, srcLeft / width);
+    const float v1 = fmax(0.0f, srcTop / height);
+    const float u2 = fmin(1.0f, srcRight / width);
+    const float v2 = fmin(1.0f, srcBottom / height);
 
     mCaches.unbindMeshBuffer();
     resetDrawTextureTexCoords(u1, v1, u2, v2);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 923978f..5bd0d4f 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -31,6 +31,12 @@
 // If turned on, text is interpreted as glyphs instead of UTF-16
 #define RENDER_TEXT_AS_GLYPHS 1
 
+// Indicates whether to remove the biggest layers first, or the smaller ones
+#define LAYER_REMOVE_BIGGEST_FIRST 0
+
+// Textures used by layers must have dimensions multiples of this number
+#define LAYER_SIZE 64
+
 /**
  * Debug level for app developers.
  */
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f9efd3c..e3ef717 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1715,161 +1715,54 @@
         }
     }
 
-    /**
-     * Acts as a proxy between AudioService and the RemoteControlClient
-     */
-    private IRemoteControlClientDispatcher mRcClientDispatcher =
-            new IRemoteControlClientDispatcher.Stub() {
-
-        public String getMetadataStringForClient(String clientName, int field) {
-            RemoteControlClient realClient;
-            synchronized(mRcClientMap) {
-                realClient = mRcClientMap.get(clientName);
-            }
-            if (realClient != null) {
-                return realClient.getMetadataString(field);
-            } else {
-                return null;
-            }
-        }
-
-        public int getPlaybackStateForClient(String clientName) {
-            RemoteControlClient realClient;
-            synchronized(mRcClientMap) {
-                realClient = mRcClientMap.get(clientName);
-            }
-            if (realClient != null) {
-                return realClient.getPlaybackState();
-            } else {
-                return 0;
-            }
-        }
-
-        public int getTransportControlFlagsForClient(String clientName) {
-            RemoteControlClient realClient;
-            synchronized(mRcClientMap) {
-                realClient = mRcClientMap.get(clientName);
-            }
-            if (realClient != null) {
-                return realClient.getTransportControlFlags();
-            } else {
-                return 0;
-            }
-        }
-
-        public Bitmap getAlbumArtForClient(String clientName, int maxWidth, int maxHeight) {
-            RemoteControlClient realClient;
-            synchronized(mRcClientMap) {
-                realClient = mRcClientMap.get(clientName);
-            }
-            if (realClient != null) {
-                return realClient.getAlbumArt(maxWidth, maxHeight);
-            } else {
-                return null;
-            }
-        }
-    };
-
-    private HashMap<String, RemoteControlClient> mRcClientMap =
-            new HashMap<String, RemoteControlClient>();
-
-    private String getIdForRcClient(RemoteControlClient client) {
-        // client is guaranteed to be non-null
-        return client.toString();
-    }
 
     /**
      * @hide
+     * CANDIDATE FOR SDK
      * Registers the remote control client for providing information to display on the remote
      * controls.
-     * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
-     *      that will receive the media button intent, and associated with the remote control
-     *      client. This method has no effect if
-     *      {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
-     *      with the same eventReceiver, or if
-     *      {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
-     * @param rcClient the remote control client associated with the event receiver, responsible
+     * @param rcClient the remote control client associated responsible
      *      for providing the information to display on the remote control.
      */
-    public void registerRemoteControlClient(ComponentName eventReceiver,
-            RemoteControlClient rcClient) {
-        if ((eventReceiver == null) || (rcClient == null)) {
+    public void registerRemoteControlClient(RemoteControlClient rcClient) {
+        if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
             return;
         }
-        String clientKey = getIdForRcClient(rcClient);
-        synchronized(mRcClientMap) {
-            if (mRcClientMap.containsKey(clientKey)) {
-                return;
-            }
-            mRcClientMap.put(clientKey, rcClient);
-        }
         IAudioService service = getService();
         try {
-            service.registerRemoteControlClient(eventReceiver, mRcClientDispatcher, clientKey,
+            service.registerRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
+                    rcClient.getIRemoteControlClient(),                        /* rcClient      */
+                    rcClient.toString(),                                       /* clientName    */
                     // used to match media button event receiver and audio focus
-                    mContext.getPackageName());
+                    mContext.getPackageName());                                /* packageName   */
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
-            synchronized(mRcClientMap) {
-                mRcClientMap.remove(clientKey);
-            }
         }
     }
 
     /**
      * @hide
+     * CANDIDATE FOR SDK
      * Unregisters the remote control client that was providing information to display on the
      * remotes.
-     * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
-     *      that receives the media button intent, and associated with the remote control
-     *      client.
      * @param rcClient the remote control client to unregister
-     * @see #registerRemoteControlClient(ComponentName, RemoteControlClient)
+     * @see #registerRemoteControlClient(RemoteControlClient)
      */
-    public void unregisterRemoteControlClient(ComponentName eventReceiver,
-            RemoteControlClient rcClient) {
-        if ((eventReceiver == null) || (rcClient == null)) {
+    public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
+        if ((rcClient == null) || (rcClient.getRcEventReceiver() == null)) {
             return;
         }
         IAudioService service = getService();
         try {
-            // remove locally
-            boolean unregister = true;
-            synchronized(mRcClientMap) {
-                if (mRcClientMap.remove(getIdForRcClient(rcClient)) == null) {
-                    unregister = false;
-                }
-            }
-            if (unregister) {
-                // unregistering a RemoteControlClient is equivalent to setting it to null
-                service.registerRemoteControlClient(eventReceiver, null, null,
-                        mContext.getPackageName());
-            }
+            service.unregisterRemoteControlClient(rcClient.getRcEventReceiver(), /* eventReceiver */
+                    rcClient.getIRemoteControlClient());                         /* rcClient      */
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
         }
     }
 
-    /**
-     * @hide
-     * Returns the current remote control client.
-     * @param rcClientId the generation counter that matches the extra
-     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT_GENERATION} in the
-     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
-     * @return the current RemoteControlClient from which information to display on the remote
-     *     control can be retrieved, or null if rcClientId doesn't match the current generation
-     *     counter.
-     */
-    public IRemoteControlClientDispatcher getRemoteControlClientDispatcher(int rcClientId) {
-        IAudioService service = getService();
-        try {
-            return service.getRemoteControlClientDispatcher(rcClientId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getRemoteControlClient "+e);
-            return null;
-        }
-    }
 
+    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
      * Broadcast intent action indicating that the displays on the remote controls
@@ -1882,6 +1775,7 @@
     public static final String REMOTE_CONTROL_CLIENT_CHANGED =
             "android.media.REMOTE_CONTROL_CLIENT_CHANGED";
 
+    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
      * The IRemoteControlClientDispatcher monotonically increasing generation counter.
@@ -1891,6 +1785,7 @@
     public static final String EXTRA_REMOTE_CONTROL_CLIENT_GENERATION =
             "android.media.EXTRA_REMOTE_CONTROL_CLIENT_GENERATION";
 
+    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
      * The name of the RemoteControlClient.
@@ -1902,6 +1797,7 @@
     public static final String EXTRA_REMOTE_CONTROL_CLIENT_NAME =
             "android.media.EXTRA_REMOTE_CONTROL_CLIENT_NAME";
 
+    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
      * The media button event receiver associated with the RemoteControlClient.
@@ -1913,6 +1809,7 @@
     public static final String EXTRA_REMOTE_CONTROL_EVENT_RECEIVER =
             "android.media.EXTRA_REMOTE_CONTROL_EVENT_RECEIVER";
 
+    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
      * The flags describing what information has changed in the current remote control client.
@@ -1923,33 +1820,6 @@
             "android.media.EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED";
 
     /**
-     * @hide
-     * Notifies the users of the associated remote control client that the information to display
-     * has changed.
-     @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
-     *      that will receive the media button intent, and associated with the remote control
-     *      client. This method has no effect if
-     *      {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
-     *      with the same eventReceiver, or if
-     *      {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
-     * @param infoFlag the type of information that has changed since this method was last called,
-     *      or the event receiver was registered. Use one or multiple of the following flags to
-     *      describe what changed:
-     *      {@link RemoteControlClient#FLAG_INFORMATION_CHANGED_METADATA},
-     *      {@link RemoteControlClient#FLAG_INFORMATION_CHANGED_KEY_MEDIA},
-     *      {@link RemoteControlClient#FLAG_INFORMATION_CHANGED_PLAYSTATE},
-     *      {@link RemoteControlClient#FLAG_INFORMATION_CHANGED_ALBUM_ART}.
-     */
-    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver, int infoFlag) {
-        IAudioService service = getService();
-        try {
-            service.notifyRemoteControlInformationChanged(eventReceiver, infoFlag);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in refreshRemoteControlDisplay"+e);
-        }
-    }
-
-    /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
      *  agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 85c7dba..acc2b23 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -34,7 +34,6 @@
 import android.database.ContentObserver;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
-import android.media.IRemoteControlClientDispatcher;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -1557,17 +1556,14 @@
         int newRingerMode = mRingerMode;
 
         if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
-            if ((direction == AudioManager.ADJUST_LOWER) && ((oldIndex + 5) / 10 <= 1)) {
-                // enter silent mode if current index is the last audible one and not repeating a
-                // volume key down
-                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
-                    // "silent mode", but which one?
-                    newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1
-                        ? AudioManager.RINGER_MODE_VIBRATE
-                        : AudioManager.RINGER_MODE_SILENT;
-                } else {
-                    adjustVolumeIndex = false;
-                }
+            // audible mode, at the bottom of the scale
+            if ((direction == AudioManager.ADJUST_LOWER &&
+                 mPrevVolDirection != AudioManager.ADJUST_LOWER) &&
+                ((oldIndex + 5) / 10 == 0)) {
+                // "silent mode", but which one?
+                newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1
+                    ? AudioManager.RINGER_MODE_VIBRATE
+                    : AudioManager.RINGER_MODE_SILENT;
             }
         } else {
             if (direction == AudioManager.ADJUST_RAISE) {
@@ -2170,45 +2166,12 @@
                     break;
 
                 case MSG_RCDISPLAY_CLEAR:
-                    // TODO remove log before release
-                    Log.i(TAG, "Clear remote control display");
-                    Intent clearIntent = new Intent(AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
-                    // no extra means no IRemoteControlClientDispatcher, which is a request to clear
-                    clearIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                    mContext.sendBroadcast(clearIntent);
+                    onRcDisplayClear();
                     break;
 
                 case MSG_RCDISPLAY_UPDATE:
-                    synchronized(mCurrentRcLock) {
-                        // msg.obj is guaranteed to be non null
-                        RemoteControlStackEntry rcse = (RemoteControlStackEntry)msg.obj;
-                        if ((mCurrentRcClient == null) ||
-                                (!mCurrentRcClient.equals(rcse.mRcClient))) {
-                            // the remote control display owner has changed between the
-                            // the message to update the display was sent, and the time it
-                            // gets to be processed (now)
-                        } else {
-                            mCurrentRcClientGen++;
-                            // TODO remove log before release
-                            Log.i(TAG, "Display/update remote control ");
-                            Intent rcClientIntent = new Intent(
-                                    AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
-                            rcClientIntent.putExtra(
-                                    AudioManager.EXTRA_REMOTE_CONTROL_CLIENT_GENERATION,
-                                    mCurrentRcClientGen);
-                            rcClientIntent.putExtra(
-                                    AudioManager.EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED,
-                                    msg.arg1);
-                            rcClientIntent.putExtra(
-                                    AudioManager.EXTRA_REMOTE_CONTROL_EVENT_RECEIVER,
-                                    rcse.mReceiverComponent.flattenToString());
-                            rcClientIntent.putExtra(
-                                    AudioManager.EXTRA_REMOTE_CONTROL_CLIENT_NAME,
-                                    rcse.mRcClientName);
-                            rcClientIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                            mContext.sendBroadcast(rcClientIntent);
-                        }
-                    }
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
                     break;
 
                 case MSG_BT_HEADSET_CNCT_FAILED:
@@ -2896,18 +2859,18 @@
 
     private final Object mCurrentRcLock = new Object();
     /**
-     * The one remote control client to be polled for display information.
+     * The one remote control client which will receive a request for display information.
      * This object may be null.
      * Access protected by mCurrentRcLock.
      */
-    private IRemoteControlClientDispatcher mCurrentRcClient = null;
+    private IRemoteControlClient mCurrentRcClient = null;
 
     private final static int RC_INFO_NONE = 0;
     private final static int RC_INFO_ALL =
-        RemoteControlClient.FLAG_INFORMATION_CHANGED_ALBUM_ART |
-        RemoteControlClient.FLAG_INFORMATION_CHANGED_KEY_MEDIA |
-        RemoteControlClient.FLAG_INFORMATION_CHANGED_METADATA |
-        RemoteControlClient.FLAG_INFORMATION_CHANGED_PLAYSTATE;
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
 
     /**
      * A monotonically increasing generation counter for mCurrentRcClient.
@@ -2917,25 +2880,6 @@
     private int mCurrentRcClientGen = 0;
 
     /**
-     * Returns the current remote control client.
-     * @param rcClientId the counter value that matches the extra
-     *     {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT_GENERATION} in the
-     *     {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
-     * @return the current IRemoteControlClientDispatcher from which information to display on the
-     *     remote control can be retrieved, or null if rcClientId doesn't match the current
-     *     generation counter.
-     */
-    public IRemoteControlClientDispatcher getRemoteControlClientDispatcher(int rcClientId) {
-        synchronized(mCurrentRcLock) {
-            if (rcClientId == mCurrentRcClientGen) {
-                return mCurrentRcClient;
-            } else {
-                return null;
-            }
-        }
-    }
-
-    /**
      * Inner class to monitor remote control client deaths, and remove the client for the
      * remote control stack if necessary.
      */
@@ -2968,7 +2912,7 @@
         public int mCallingUid;
 
         /** provides access to the information to display on the remote control */
-        public IRemoteControlClientDispatcher mRcClient;
+        public IRemoteControlClient mRcClient;
         public RcClientDeathHandler mRcClientDeathHandler;
 
         public RemoteControlStackEntry(ComponentName r) {
@@ -3122,6 +3066,103 @@
         return false;
     }
 
+    //==========================================================================================
+    // Remote control display / client
+    //==========================================================================================
+    /**
+     * Update the remote control displays with the new "focused" client generation
+     */
+    private void setNewRcClientGenerationOnDisplays_syncRcStack(int newClientGeneration) {
+        // NOTE: Only one IRemoteControlDisplay supported in this implementation
+        if (mRcDisplay != null) {
+            try {
+                mRcDisplay.setCurrentClientGenerationId(newClientGeneration);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead display in onRcDisplayUpdate() "+e);
+                // if we had a display before, stop monitoring its death
+                rcDisplay_stopDeathMonitor_syncRcStack();
+                mRcDisplay = null;
+            }
+        }
+    }
+
+    /**
+     * Update the remote control clients with the new "focused" client generation
+     */
+    private void setNewRcClientGenerationOnClients_syncRcStack(int newClientGeneration) {
+        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+        while(stackIterator.hasNext()) {
+            RemoteControlStackEntry se = stackIterator.next();
+            if ((se != null) && (se.mRcClient != null)) {
+                try {
+                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Dead client in onRcDisplayUpdate()"+e);
+                    stackIterator.remove();
+                    se.unlinkToRcClientDeath();
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the displays and clients with the new "focused" client generation
+     */
+    private void setNewRcClientGeneration(int newClientGeneration) {
+        synchronized(mRCStack) {
+            // send the new valid client generation ID to all displays
+            setNewRcClientGenerationOnDisplays_syncRcStack(newClientGeneration);
+            // send the new valid client generation ID to all clients
+            setNewRcClientGenerationOnClients_syncRcStack(newClientGeneration);
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_CLEAR event
+     */
+    private void onRcDisplayClear() {
+        // TODO remove log before release
+        Log.i(TAG, "Clear remote control display");
+
+        synchronized(mCurrentRcLock) {
+            mCurrentRcClientGen++;
+
+            // synchronously update the displays and clients with the new client generation
+            setNewRcClientGeneration(mCurrentRcClientGen);
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_UPDATE event
+     */
+    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
+        synchronized(mCurrentRcLock) {
+            if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
+                // TODO remove log before release
+                Log.i(TAG, "Display/update remote control ");
+
+                mCurrentRcClientGen++;
+
+                // synchronously update the displays and clients with the new client generation
+                setNewRcClientGeneration(mCurrentRcClientGen);
+
+                // ask the current client that it needs to send info
+                try {
+                    mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
+                            flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Current valid remote client is dead: "+e);
+                    mCurrentRcClient = null;
+                }
+            } else {
+                // the remote control display owner has changed between the
+                // the message to update the display was sent, and the time it
+                // gets to be processed (now)
+            }
+        }
+    }
+
+
     /**
      * Helper function:
      * Called synchronized on mRCStack
@@ -3130,6 +3171,7 @@
         synchronized(mCurrentRcLock) {
             mCurrentRcClient = null;
         }
+        // will cause onRcDisplayClear() to be called in AudioService's handler thread
         mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
     }
 
@@ -3155,6 +3197,7 @@
             }
             mCurrentRcClient = rcse.mRcClient;
         }
+        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
         mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
                 infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
     }
@@ -3223,7 +3266,7 @@
 
     /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
     public void registerRemoteControlClient(ComponentName eventReceiver,
-            IRemoteControlClientDispatcher rcClient, String clientName, String callingPackageName) {
+            IRemoteControlClient rcClient, String clientName, String callingPackageName) {
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
                 // store the new display information
@@ -3238,6 +3281,14 @@
                         }
                         // save the new remote control client
                         rcse.mRcClient = rcClient;
+                        if (mRcDisplay != null) {
+                            try {
+                                rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Error connecting remote control display to client: "+e);
+                                e.printStackTrace();
+                            }
+                        }
                         rcse.mCallingPackageName = callingPackageName;
                         rcse.mRcClientName = clientName;
                         rcse.mCallingUid = Binder.getCallingUid();
@@ -3269,18 +3320,121 @@
         }
     }
 
-    /** see AudioManager.notifyRemoteControlInformationChanged(ComponentName er, int infoFlag) */
-    public void notifyRemoteControlInformationChanged(ComponentName eventReceiver, int infoFlag) {
-        synchronized(mAudioFocusLock) {
+    /** see AudioManager.unregisterRemoteControlClient(ComponentName eventReceiver, ...) */
+    public void unregisterRemoteControlClient(ComponentName eventReceiver,
+            IRemoteControlClient rcClient) {
+        //FIXME implement
+    }
+
+    /**
+     * The remote control displays.
+     * Access synchronized on mRCStack
+     * NOTE: Only one IRemoteControlDisplay supported in this implementation
+     */
+    private IRemoteControlDisplay mRcDisplay;
+    private RcDisplayDeathHandler mRcDisplayDeathHandler;
+    private int mArtworkExpectedWidth = -1;
+    private int mArtworkExpectedHeight = -1;
+    /**
+     * Inner class to monitor remote control display deaths, and unregister them from the list
+     * of displays if necessary.
+     */
+    private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
+        public void binderDied() {
             synchronized(mRCStack) {
-                // only refresh if the eventReceiver is at the top of the stack
-                if (isCurrentRcController(eventReceiver)) {
-                    checkUpdateRemoteControlDisplay(infoFlag);
+                Log.w(TAG, "  RemoteControl: display died");
+                mRcDisplay = null;
+            }
+        }
+
+    }
+
+    private void rcDisplay_stopDeathMonitor_syncRcStack() {
+        if (mRcDisplay != null) {
+            // we had a display before, stop monitoring its death
+            IBinder b = mRcDisplay.asBinder();
+            try {
+                b.unlinkToDeath(mRcDisplayDeathHandler, 0);
+            } catch (java.util.NoSuchElementException e) {
+             // being conservative here
+                Log.e(TAG, "Error while trying to unlink display death handler " + e);
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private void rcDisplay_startDeathMonitor_syncRcStack() {
+        if (mRcDisplay != null) {
+            // new non-null display, monitor its death
+            IBinder b = mRcDisplay.asBinder();
+            mRcDisplayDeathHandler = new RcDisplayDeathHandler();
+            try {
+                b.linkToDeath(mRcDisplayDeathHandler, 0);
+            } catch (RemoteException e) {
+                // remote control display is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
+                mRcDisplay = null;
+            }
+        }
+    }
+
+    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        synchronized(mRCStack) {
+            if (mRcDisplay == rcd) {
+                return;
+            }
+            // if we had a display before, stop monitoring its death
+            rcDisplay_stopDeathMonitor_syncRcStack();
+            mRcDisplay = rcd;
+            // new display, start monitoring its death
+            rcDisplay_startDeathMonitor_syncRcStack();
+
+            // let all the remote control clients there is a new display
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                if(rcse.mRcClient != null) {
+                    try {
+                        rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error connecting remote control display to client: " + e);
+                        e.printStackTrace();
+                    }
                 }
             }
         }
     }
 
+    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        synchronized(mRCStack) {
+            // if we had a display before, stop monitoring its death
+            rcDisplay_stopDeathMonitor_syncRcStack();
+            mRcDisplay = null;
+
+            // disconnect this remote control display from all the clients
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                if(rcse.mRcClient != null) {
+                    try {
+                        rcse.mRcClient.unplugRemoteControlDisplay(rcd);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error disconnecting remote control display to client: " + e);
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mRCStack) {
+            // NOTE: Only one IRemoteControlDisplay supported in this implementation
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         // TODO probably a lot more to do here than just the audio focus and remote control stacks
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7f9ced9..7bf9814 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,7 +18,8 @@
 
 import android.content.ComponentName;
 import android.media.IAudioFocusDispatcher;
-import android.media.IRemoteControlClientDispatcher;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteControlDisplay;
 
 /**
  * {@hide}
@@ -88,13 +89,14 @@
 
     void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
 
-    void registerRemoteControlClient(in ComponentName eventReceiver,
-           in IRemoteControlClientDispatcher rcClient, in String clientName,
-           in String callingPackageName);
+    oneway void registerRemoteControlClient(in ComponentName eventReceiver,
+           in IRemoteControlClient rcClient, in String clientName, in String callingPackageName);
+    oneway void unregisterRemoteControlClient(in ComponentName eventReceiver,
+           in IRemoteControlClient rcClient);
 
-    IRemoteControlClientDispatcher getRemoteControlClientDispatcher(in int rcClientId);
-
-    void notifyRemoteControlInformationChanged(in ComponentName eventReceiver, int infoFlag);
+    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd);
+    oneway void unregisterRemoteControlDisplay(in IRemoteControlDisplay rcd);
+    oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
 
     void startBluetoothSco(IBinder cb);
 
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
new file mode 100644
index 0000000..0fbba20
--- /dev/null
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -0,0 +1,51 @@
+/* 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.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+import android.media.IRemoteControlDisplay;
+
+/**
+ * @hide
+ * Interface registered by AudioManager to notify a source of remote control information
+ * that information is requested to be displayed on the remote control (through
+ * IRemoteControlDisplay).
+ * {@see AudioManager#registerRemoteControlClient(RemoteControlClient)}.
+ */
+oneway interface IRemoteControlClient
+{
+    /**
+     * Notifies a remote control client that information for the given generation ID is
+     * requested. If the flags contains
+     * {@link RemoteControlClient#FLAG_INFORMATION_REQUESTED_ALBUM_ART} then the width and height
+     *   parameters are valid.
+     * @param generationId
+     * @param infoFlags
+     * @param artWidth if > 0, artHeight must be > 0 too.
+     * @param artHeight
+     * FIXME: is infoFlags required? since the RCC pushes info, this might always be called
+     *        with RC_INFO_ALL
+     */
+    void onInformationRequested(int generationId, int infoFlags, int artWidth, int artHeight);
+
+    /**
+     * Sets the generation counter of the current client that is displayed on the remote control.
+     */
+    void setCurrentClientGenerationId(int clientGeneration);
+
+    void   plugRemoteControlDisplay(IRemoteControlDisplay rcd);
+    void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
+}
\ No newline at end of file
diff --git a/media/java/android/media/IRemoteControlClientDispatcher.aidl b/media/java/android/media/IRemoteControlClientDispatcher.aidl
deleted file mode 100644
index 98142cc..0000000
--- a/media/java/android/media/IRemoteControlClientDispatcher.aidl
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.
- */
-
-package android.media;
-
-import android.graphics.Bitmap;
-
-/**
- * @hide
- * Interface registered by AudioManager to dispatch remote control information requests
- * to the RemoteControlClient implementation. This is used by AudioService.
- * {@see AudioManager#registerRemoteControlClient(ComponentName, RemoteControlClient)}.
- */
-interface IRemoteControlClientDispatcher
-{
-    /**
-     * Called by a remote control to retrieve a String of information to display.
-     * @param field the identifier for a metadata field to retrieve. Valid values are
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
-     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
-     * @return null if the requested field is not supported, or the String matching the
-     *       metadata field.
-     */
-    String getMetadataStringForClient(String clientName, int field);
-
-    /**
-     * Called by a remote control to retrieve the current playback state.
-     * @return one of the following values:
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_STOPPED},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_PAUSED},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_PLAYING},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_FAST_FORWARDING},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_REWINDING},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_SKIPPING_FORWARDS},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_SKIPPING_BACKWARDS},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_BUFFERING},
-     *       {@link android.media.AudioManager.RemoteControlParameters#PLAYSTATE_ERROR}.
-     */
-    int getPlaybackStateForClient(String clientName);
-
-    /**
-     * Called by a remote control to retrieve the flags for the media transport control buttons
-     * that this client supports.
-     * @see {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_PREVIOUS},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_REWIND},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_PLAY},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_PLAY_PAUSE},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_PAUSE},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_STOP},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_FAST_FORWARD},
-     *      {@link android.media.AudioManager.RemoteControlParameters#FLAG_KEY_MEDIA_NEXT}
-     */
-    int getTransportControlFlagsForClient(String clientName);
-
-    /**
-     * Called by a remote control to retrieve the album art picture at the requested size.
-     * Note that returning a bitmap smaller than the maximum requested dimension is accepted
-     * and it will be scaled as needed, but exceeding the maximum dimensions may produce
-     * unspecified results, such as the image being cropped or simply not being displayed.
-     * @param maxWidth the maximum width of the requested bitmap expressed in pixels.
-     * @param maxHeight the maximum height of the requested bitmap expressed in pixels.
-     * @return the bitmap for the album art, or null if there isn't any.
-     * @see android.graphics.Bitmap
-     */
-    Bitmap getAlbumArtForClient(String clientName, int maxWidth, int maxHeight);
-}
diff --git a/media/java/android/media/IRemoteControlDisplay.aidl b/media/java/android/media/IRemoteControlDisplay.aidl
new file mode 100644
index 0000000..19ea202
--- /dev/null
+++ b/media/java/android/media/IRemoteControlDisplay.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+
+/**
+ * @hide
+ * Interface registered through AudioManager of an object that displays information
+ * received from a remote control client.
+ * {@see AudioManager#registerRemoteControlDisplay(IRemoteControlDisplay)}.
+ */
+oneway interface IRemoteControlDisplay
+{
+    /**
+     * Sets the generation counter of the current client that is displayed on the remote control.
+     */
+    void setCurrentClientGenerationId(int clientGeneration);
+
+    void setPlaybackState(int generationId, int state);
+
+    void setMetadata(int generationId, in Bundle metadata);
+
+    void setTransportControlFlags(int generationId, int transportControlFlags);
+
+    void setArtwork(int generationId, in Bitmap artwork);
+}
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index c384636..bfe08b9 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -17,69 +17,84 @@
 package android.media;
 
 import android.content.ComponentName;
+import android.content.SharedPreferences.Editor;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
 
 /**
  * @hide
- * Interface for an object that exposes information meant to be consumed by remote controls
+ * CANDIDATE FOR SDK
+ * RemoteControlClient enables exposing information meant to be consumed by remote controls
  * capable of displaying metadata, album art and media transport control buttons.
- * Such a remote control client object is associated with a media button event receiver
+ * A remote control client object is associated with a media button event receiver
  * when registered through
- * {@link AudioManager#registerRemoteControlClient(ComponentName, RemoteControlClient)}.
+ * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
  */
-public interface RemoteControlClient
+public class RemoteControlClient
 {
+    private final static String TAG = "RemoteControlClient";
+
     /**
      * Playback state of a RemoteControlClient which is stopped.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_STOPPED            = 1;
     /**
      * Playback state of a RemoteControlClient which is paused.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_PAUSED             = 2;
     /**
      * Playback state of a RemoteControlClient which is playing media.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_PLAYING            = 3;
     /**
      * Playback state of a RemoteControlClient which is fast forwarding in the media
      *    it is currently playing.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_FAST_FORWARDING    = 4;
     /**
      * Playback state of a RemoteControlClient which is fast rewinding in the media
      *    it is currently playing.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_REWINDING          = 5;
     /**
      * Playback state of a RemoteControlClient which is skipping to the next
      *    logical chapter (such as a song in a playlist) in the media it is currently playing.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
     /**
      * Playback state of a RemoteControlClient which is skipping back to the previous
      *    logical chapter (such as a song in a playlist) in the media it is currently playing.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
     /**
      * Playback state of a RemoteControlClient which is buffering data to play before it can
      *    start or resume playback.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_BUFFERING          = 8;
     /**
@@ -88,98 +103,188 @@
      *    connectivity when attempting to stream data from a server, or expired user credentials
      *    when trying to play subscription-based content.
      *
-     * @see android.media.RemoteControlClient#getPlaybackState()
+     * @see #setPlaybackState(int)
      */
     public final static int PLAYSTATE_ERROR              = 9;
+    /**
+     * @hide
+     * The value of a playback state when none has been declared
+     */
+    public final static int PLAYSTATE_NONE               = 0;
 
     /**
      * Flag indicating a RemoteControlClient makes use of the "previous" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS
      */
     public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
     /**
      * Flag indicating a RemoteControlClient makes use of the "rewing" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
      */
     public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
     /**
      * Flag indicating a RemoteControlClient makes use of the "play" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY
      */
     public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
     /**
      * Flag indicating a RemoteControlClient makes use of the "play/pause" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE
      */
     public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
     /**
      * Flag indicating a RemoteControlClient makes use of the "pause" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE
      */
     public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
     /**
      * Flag indicating a RemoteControlClient makes use of the "stop" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP
      */
     public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
     /**
      * Flag indicating a RemoteControlClient makes use of the "fast forward" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD
      */
     public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
     /**
      * Flag indicating a RemoteControlClient makes use of the "next" media key.
      *
-     * @see android.media.RemoteControlClient#getTransportControlFlags()
+     * @see #setTransportControlFlags(int)
      * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
      */
     public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
 
     /**
-     * Flag used to signal that the metadata exposed by the RemoteControlClient has changed.
-     *
-     * @see #notifyRemoteControlInformationChanged(ComponentName, int)
+     * @hide
+     * The flags for when no media keys are declared supported
      */
-    public final static int FLAG_INFORMATION_CHANGED_METADATA = 1 << 0;
+    public final static int FLAGS_KEY_MEDIA_NONE = 0;
+
     /**
+     * @hide
+     * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested.
+     */
+    public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
+    /**
+     * @hide
+     * FIXME doc not valid
      * Flag used to signal that the transport control buttons supported by the
      * RemoteControlClient have changed.
      * This can for instance happen when playback is at the end of a playlist, and the "next"
      * operation is not supported anymore.
-     *
-     * @see #notifyRemoteControlInformationChanged(ComponentName, int)
      */
-    public final static int FLAG_INFORMATION_CHANGED_KEY_MEDIA = 1 << 1;
+    public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
     /**
+     * @hide
+     * FIXME doc not valid
      * Flag used to signal that the playback state of the RemoteControlClient has changed.
-     *
-     * @see #notifyRemoteControlInformationChanged(ComponentName, int)
      */
-    public final static int FLAG_INFORMATION_CHANGED_PLAYSTATE = 1 << 2;
+    public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
     /**
+     * @hide
+     * FIXME doc not valid
      * Flag used to signal that the album art for the RemoteControlClient has changed.
-     *
-     * @see #notifyRemoteControlInformationChanged(ComponentName, int)
      */
-    public final static int FLAG_INFORMATION_CHANGED_ALBUM_ART = 1 << 3;
+    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
 
     /**
-     * Called by a remote control to retrieve a String of information to display.
-     * @param field the identifier for a metadata field to retrieve. Valid values are
+     * Class constructor.
+     * @param mediaButtonEventReceiver the receiver for the media button events.
+     * @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");
+        }
+    }
+
+    /**
+     * 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.
+     * @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 used to modify metadata in a {@link RemoteControlClient} object.
+     */
+    public class MetadataEditor {
+
+        private MetadataEditor() { /* only use factory */ }
+
+        public MetadataEditor putString(int key, String value) {
+            return this;
+        }
+
+        public MetadataEditor putBitmap(int key, Bitmap bitmap) {
+            return this;
+        }
+
+        public void clear() {
+
+        }
+
+        public void apply() {
+
+        }
+    }
+
+    public MetadataEditor editMetadata(boolean startEmpty) {
+        return (new MetadataEditor());
+    }
+
+
+    /**
+     * @hide
+     * FIXME migrate this functionality under MetadataEditor
+     * Start collecting information to be displayed.
+     * Use {@link #commitMetadata()} to signal the end of the collection which has been created
+     *  through one or multiple calls to {@link #addMetadataString(int, int, String)}.
+     */
+    public void startMetadata() {
+        synchronized(mCacheLock) {
+            mMetadata.clear();
+        }
+    }
+
+    /**
+     * @hide
+     * FIXME migrate this functionality under MetadataEditor
+     * Adds textual information to be displayed.
+     * Note that none of the information added before {@link #startMetadata()},
+     * and after {@link #commitMetadata()} has been called, will be displayed.
+     * @param key the identifier of a the metadata field to set. Valid values are
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
@@ -195,14 +300,54 @@
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
-     * @return null if the requested field is not supported, or the String matching the
-     *       metadata field.
+     * @param value the String for the field value, or null to signify there is no valid
+     *      information for the field.
      */
-    String getMetadataString(int field);
+    public void addMetadataString(int key, String value) {
+        synchronized(mCacheLock) {
+            // store locally
+            mMetadata.putString(String.valueOf(key), value);
+        }
+    }
 
     /**
-     * Called by a remote control to retrieve the current playback state.
-     * @return one of the following values:
+     * @hide
+     * FIXME migrate this functionality under MetadataEditor
+     * Marks all the metadata previously set with {@link #addMetadataString(int, int, String)} as
+     * eligible to be displayed.
+     */
+    public void commitMetadata() {
+        synchronized(mCacheLock) {
+            // send to remote control display if conditions are met
+            sendMetadata_syncCacheLock();
+        }
+    }
+
+    /**
+     * @hide
+     * FIXME migrate this functionality under MetadataEditor
+     * Sets the album / artwork picture to be displayed on the remote control.
+     * @param artwork the bitmap for the artwork, or null if there isn't any.
+     * @see android.graphics.Bitmap
+     */
+    public void setArtwork(Bitmap artwork) {
+        synchronized(mCacheLock) {
+            // resize and store locally
+            if (mArtworkExpectedWidth > 0) {
+                mArtwork = scaleBitmapIfTooBig(artwork,
+                        mArtworkExpectedWidth, mArtworkExpectedHeight);
+            } else {
+                // no valid resize dimensions, store as is
+                mArtwork = artwork;
+            }
+            // send to remote control display if conditions are met
+            sendArtwork_syncCacheLock();
+        }
+    }
+
+    /**
+     * Sets the current playback state.
+     * @param state the current playback state, one of the following values:
      *       {@link #PLAYSTATE_STOPPED},
      *       {@link #PLAYSTATE_PAUSED},
      *       {@link #PLAYSTATE_PLAYING},
@@ -213,12 +358,20 @@
      *       {@link #PLAYSTATE_BUFFERING},
      *       {@link #PLAYSTATE_ERROR}.
      */
-    int getPlaybackState();
+    public void setPlaybackState(int state) {
+        synchronized(mCacheLock) {
+            // store locally
+            mPlaybackState = state;
+
+            // send to remote control display if conditions are met
+            sendPlaybackState_syncCacheLock();
+        }
+    }
 
     /**
-     * Called by a remote control to retrieve the flags for the media transport control buttons
-     * that this client supports.
-     * @see {@link #FLAG_KEY_MEDIA_PREVIOUS},
+     * Sets the flags for the media transport control buttons that this client supports.
+     * @param a combination of the following flags:
+     *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
      *      {@link #FLAG_KEY_MEDIA_REWIND},
      *      {@link #FLAG_KEY_MEDIA_PLAY},
      *      {@link #FLAG_KEY_MEDIA_PLAY_PAUSE},
@@ -227,17 +380,311 @@
      *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
      *      {@link #FLAG_KEY_MEDIA_NEXT}
      */
-    int getTransportControlFlags();
+    public void setTransportControlFlags(int transportControlFlags) {
+        synchronized(mCacheLock) {
+            // store locally
+            mTransportControlFlags = transportControlFlags;
+
+            // send to remote control display if conditions are met
+            sendTransportControlFlags_syncCacheLock();
+        }
+    }
 
     /**
-     * Called by a remote control to retrieve the album art picture at the requested size.
-     * Note that returning a bitmap smaller than the maximum requested dimension is accepted
-     * and it will be scaled as needed, but exceeding the maximum dimensions may produce
-     * unspecified results, such as the image being cropped or simply not being displayed.
-     * @param maxWidth the maximum width of the requested bitmap expressed in pixels.
-     * @param maxHeight the maximum height of the requested bitmap expressed in pixels.
-     * @return the bitmap for the album art, or null if there isn't any.
-     * @see android.graphics.Bitmap
+     * Lock for all cached data
      */
-    Bitmap getAlbumArt(int maxWidth, int maxHeight);
+    private final Object mCacheLock = new Object();
+    /**
+     * Cache for the playback state.
+     * Access synchronized on mCacheLock
+     */
+    private int mPlaybackState = PLAYSTATE_NONE;
+    /**
+     * Cache for the artwork bitmap.
+     * Access synchronized on mCacheLock
+     */
+    private Bitmap mArtwork;
+    private final int ARTWORK_DEFAULT_SIZE = 256;
+    private int mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
+    private int mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
+    /**
+     * Cache for the transport control mask.
+     * Access synchronized on mCacheLock
+     */
+    private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE;
+    /**
+     * Cache for the metadata strings.
+     * Access synchronized on mCacheLock
+     */
+    private Bundle mMetadata = new Bundle();
+    /**
+     * The current remote control client generation ID across the system
+     */
+    private int mCurrentClientGenId = -1;
+    /**
+     * The remote control client generation ID, the last time it was told it was the current RC.
+     * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
+     * client is the "focused" one, and that whenever this client's info is updated, it needs to
+     * send it to the known IRemoteControlDisplay interfaces.
+     */
+    private int mInternalClientGenId = -2;
+
+    /**
+     * The media button event receiver associated with this remote control client
+     */
+    private final ComponentName mRcEventReceiver;
+
+    /**
+     * The remote control display to which this client will send information.
+     * NOTE: Only one IRemoteControlDisplay supported in this implementation
+     */
+    private IRemoteControlDisplay mRcDisplay;
+
+    /**
+     * @hide
+     * Accessor to media button event receiver
+     */
+    public ComponentName getRcEventReceiver() {
+        return mRcEventReceiver;
+    }
+    /**
+     * @hide
+     * Accessor to IRemoteControlClient
+     */
+    public IRemoteControlClient getIRemoteControlClient() {
+        return mIRCC;
+    }
+
+    /**
+     * The IRemoteControlClient implementation
+     */
+    private IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
+
+        public void onInformationRequested(int clientGeneration, int infoFlags,
+                int artWidth, int artHeight) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                // signal new client
+                mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
+                mEventHandler.dispatchMessage(
+                        mEventHandler.obtainMessage(
+                                MSG_NEW_INTERNAL_CLIENT_GEN,
+                                artWidth, artHeight,
+                                new Integer(clientGeneration)));
+                // send the information
+                mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
+                mEventHandler.removeMessages(MSG_REQUEST_METADATA);
+                mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
+                mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
+                mEventHandler.dispatchMessage(
+                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
+                mEventHandler.dispatchMessage(
+                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+            }
+        }
+
+        public void setCurrentClientGenerationId(int clientGeneration) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                        MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
+            }
+        }
+
+        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                        MSG_PLUG_DISPLAY, rcd));
+            }
+        }
+
+        public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                        MSG_UNPLUG_DISPLAY, rcd));
+            }
+        }
+    };
+
+    private EventHandler mEventHandler;
+    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
+    private final static int MSG_REQUEST_METADATA = 2;
+    private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
+    private final static int MSG_REQUEST_ARTWORK = 4;
+    private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
+    private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
+    private final static int MSG_PLUG_DISPLAY = 7;
+    private final static int MSG_UNPLUG_DISPLAY = 8;
+
+    private class EventHandler extends Handler {
+        public EventHandler(RemoteControlClient rcc, Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_REQUEST_PLAYBACK_STATE:
+                    synchronized (mCacheLock) {
+                        sendPlaybackState_syncCacheLock();
+                    }
+                    break;
+                case MSG_REQUEST_METADATA:
+                    synchronized (mCacheLock) {
+                        sendMetadata_syncCacheLock();
+                    }
+                    break;
+                case MSG_REQUEST_TRANSPORTCONTROL:
+                    synchronized (mCacheLock) {
+                        sendTransportControlFlags_syncCacheLock();
+                    }
+                    break;
+                case MSG_REQUEST_ARTWORK:
+                    synchronized (mCacheLock) {
+                        sendArtwork_syncCacheLock();
+                    }
+                    break;
+                case MSG_NEW_INTERNAL_CLIENT_GEN:
+                    onNewInternalClientGen((Integer)msg.obj, msg.arg1, msg.arg2);
+                    break;
+                case MSG_NEW_CURRENT_CLIENT_GEN:
+                    onNewCurrentClientGen(msg.arg1);
+                    break;
+                case MSG_PLUG_DISPLAY:
+                    onPlugDisplay((IRemoteControlDisplay)msg.obj);
+                    break;
+                case MSG_UNPLUG_DISPLAY:
+                    onUnplugDisplay((IRemoteControlDisplay)msg.obj);
+                    break;
+                default:
+                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
+            }
+        }
+    }
+
+    private void sendPlaybackState_syncCacheLock() {
+        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
+            try {
+                mRcDisplay.setPlaybackState(mInternalClientGenId, mPlaybackState);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in setPlaybackState(), dead display "+e);
+                mRcDisplay = null;
+                mArtworkExpectedWidth = -1;
+                mArtworkExpectedHeight = -1;
+            }
+        }
+    }
+
+    private void sendMetadata_syncCacheLock() {
+        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
+            try {
+                mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in sendPlaybackState(), dead display "+e);
+                mRcDisplay = null;
+                mArtworkExpectedWidth = -1;
+                mArtworkExpectedHeight = -1;
+            }
+        }
+    }
+
+    private void sendTransportControlFlags_syncCacheLock() {
+        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
+            try {
+                mRcDisplay.setTransportControlFlags(mInternalClientGenId,
+                        mTransportControlFlags);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in sendTransportControlFlags(), dead display "+e);
+                mRcDisplay = null;
+                mArtworkExpectedWidth = -1;
+                mArtworkExpectedHeight = -1;
+            }
+        }
+    }
+
+    private void sendArtwork_syncCacheLock() {
+        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
+            // even though we have already scaled in setArtwork(), when this client needs to
+            // send the bitmap, there might be newer and smaller expected dimensions, so we have
+            // to check again.
+            mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
+            try {
+                mRcDisplay.setArtwork(mInternalClientGenId, mArtwork);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in sendArtwork(), dead display "+e);
+                mRcDisplay = null;
+                mArtworkExpectedWidth = -1;
+                mArtworkExpectedHeight = -1;
+            }
+        }
+    }
+
+    private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) {
+        synchronized (mCacheLock) {
+            // this remote control client is told it is the "focused" one:
+            // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
+            mInternalClientGenId = clientGeneration.intValue();
+            if (artWidth > 0) {
+                mArtworkExpectedWidth = artWidth;
+                mArtworkExpectedHeight = artHeight;
+            }
+        }
+    }
+
+    private void onNewCurrentClientGen(int clientGeneration) {
+        synchronized (mCacheLock) {
+            mCurrentClientGenId = clientGeneration;
+        }
+    }
+
+    private void onPlugDisplay(IRemoteControlDisplay rcd) {
+        synchronized(mCacheLock) {
+            mRcDisplay = rcd;
+        }
+    }
+
+    private void onUnplugDisplay(IRemoteControlDisplay rcd) {
+        synchronized(mCacheLock) {
+            if ((mRcDisplay != null) && (mRcDisplay.equals(rcd))) {
+                mRcDisplay = null;
+                mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
+                mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
+            }
+        }
+    }
+
+    /**
+     * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
+     * If the bitmap fits, then do nothing and return the original.
+     *
+     * @param bitmap
+     * @param maxWidth
+     * @param maxHeight
+     * @return
+     */
+
+    private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
+        final int width = bitmap.getWidth();
+        final int height = bitmap.getHeight();
+        if (width > maxWidth || height > maxHeight) {
+            float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
+            int newWidth = Math.round(scale * width);
+            int newHeight = Math.round(scale * height);
+            Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, bitmap.getConfig());
+            Canvas canvas = new Canvas(outBitmap);
+            Paint paint = new Paint();
+            paint.setAntiAlias(true);
+            paint.setFilterBitmap(true);
+            canvas.drawBitmap(bitmap, null,
+                    new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
+            bitmap = outBitmap;
+        }
+        return bitmap;
+
+    }
 }
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 4ca6fad..b2a279a 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -626,7 +626,7 @@
         if (getGeneratedImageClip() == null) {
             final Bitmap thumbnail = scaleImage(mFilename, width, height);
             for (int i = 0; i < indices.length; i++) {
-                callback.onThumbnail(thumbnail, i);
+                callback.onThumbnail(thumbnail, indices[i]);
             }
         } else {
             if (startMs > endMs) {
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index f0a330f..2abdb56 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -378,24 +378,36 @@
             // fall through
         }
 
-        if (mUpsamplingFactor == 2) {
-            if (mConfig->desiredChannels == 1) {
-                memcpy(&mConfig->pOutputBuffer[1024],
-                       &mConfig->pOutputBuffer[2048],
-                       numOutBytes * 2);
+        if (decoderErr == MP4AUDEC_SUCCESS || mNumSamplesOutput > 0) {
+            // We'll only output data if we successfully decoded it or
+            // we've previously decoded valid data, in the latter case
+            // (decode failed) we'll output a silent frame.
+
+            if (mUpsamplingFactor == 2) {
+                if (mConfig->desiredChannels == 1) {
+                    memcpy(&mConfig->pOutputBuffer[1024],
+                           &mConfig->pOutputBuffer[2048],
+                           numOutBytes * 2);
+                }
+                numOutBytes *= 2;
             }
-            numOutBytes *= 2;
+
+            outHeader->nFilledLen = numOutBytes;
+            outHeader->nFlags = 0;
+
+            outHeader->nTimeStamp =
+                mAnchorTimeUs
+                    + (mNumSamplesOutput * 1000000ll) / mConfig->samplingRate;
+
+            mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor;
+
+            outInfo->mOwnedByUs = false;
+            outQueue.erase(outQueue.begin());
+            outInfo = NULL;
+            notifyFillBufferDone(outHeader);
+            outHeader = NULL;
         }
 
-        outHeader->nFilledLen = numOutBytes;
-        outHeader->nFlags = 0;
-
-        outHeader->nTimeStamp =
-            mAnchorTimeUs
-                + (mNumSamplesOutput * 1000000ll) / mConfig->samplingRate;
-
-        mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor;
-
         if (inHeader->nFilledLen == 0) {
             inInfo->mOwnedByUs = false;
             inQueue.erase(inQueue.begin());
@@ -404,12 +416,6 @@
             inHeader = NULL;
         }
 
-        outInfo->mOwnedByUs = false;
-        outQueue.erase(outQueue.begin());
-        outInfo = NULL;
-        notifyFillBufferDone(outHeader);
-        outHeader = NULL;
-
         if (decoderErr == MP4AUDEC_SUCCESS) {
             ++mInputBufferCount;
         }
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index e1b9991..3ef7b71 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -493,7 +493,8 @@
     : mDataSource(source),
       mReader(new DataSourceReader(mDataSource)),
       mSegment(NULL),
-      mExtractedThumbnails(false) {
+      mExtractedThumbnails(false),
+      mIsWebm(false) {
     off64_t size;
     mIsLiveStreaming =
         (mDataSource->flags()
@@ -507,6 +508,10 @@
         return;
     }
 
+    if (ebmlHeader.m_docType && !strcmp("webm", ebmlHeader.m_docType)) {
+        mIsWebm = true;
+    }
+
     long long ret =
         mkvparser::Segment::CreateInstance(mReader, pos, mSegment);
 
@@ -757,7 +762,10 @@
 
 sp<MetaData> MatroskaExtractor::getMetaData() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
+
+    meta->setCString(
+            kKeyMIMEType,
+            mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
 
     return meta;
 }
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 38ebd61..1294b4f 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -68,6 +68,7 @@
     mkvparser::Segment *mSegment;
     bool mExtractedThumbnails;
     bool mIsLiveStreaming;
+    bool mIsWebm;
 
     void addTracks();
     void findThumbnails();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 36f1659..8da2db6 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -120,6 +120,9 @@
     }
 
     public void onBeginDrag(View v) {
+        // We do this so the underlying ScrollView knows that it won't get
+        // the chance to intercept events anymore
+        requestDisallowInterceptTouchEvent(true);
     }
 
     public View getChildAtPosition(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 959328f..b1a30d9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -135,6 +135,9 @@
     }
 
     public void onBeginDrag(View v) {
+        // We do this so the underlying ScrollView knows that it won't get
+        // the chance to intercept events anymore
+        requestDisallowInterceptTouchEvent(true);
     }
 
     public View getChildAtPosition(MotionEvent ev) {
diff --git a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
index 044cf4a..6ff9a60 100644
--- a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -311,12 +311,6 @@
             mCheckingDialog.setCancelable(false);
             mCheckingDialog.getWindow().setType(
                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            if (!mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_sf_slowBlur)) {
-                mCheckingDialog.getWindow().setFlags(
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-            }
         }
         return mCheckingDialog;
     }
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index c47383a..ec31028 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -226,11 +226,6 @@
 
         final AlertDialog dialog = ab.create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        if (!mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_sf_slowBlur)) {
-            dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-        }
 
         dialog.setOnDismissListener(this);
 
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 86de558..431f8e0 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -292,7 +292,8 @@
                 mKeyguardViewProperties, mUpdateMonitor);
 
         mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);
-        mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
 
         final ContentResolver cr = mContext.getContentResolver();
         mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index adcc9c0..2d90727 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -760,12 +760,6 @@
             .setNeutralButton(R.string.ok, null)
             .create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        if (!mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_sf_slowBlur)) {
-            dialog.getWindow().setFlags(
-                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-        }
         dialog.show();
     }
 
@@ -782,6 +776,7 @@
         }
         String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(),
                 timeoutInSeconds);
+
         showDialog(null, message);
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index c929bbc..e2d6c5f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2512,8 +2512,15 @@
         a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
         a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
 
-        if (getContext().getApplicationInfo().targetSdkVersion
-                < android.os.Build.VERSION_CODES.HONEYCOMB) {
+        final Context context = getContext();
+        final int targetSdk = context.getApplicationInfo().targetSdkVersion;
+        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
+        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+        final boolean targetHcNeedsOptions = context.getResources().getBoolean(
+                com.android.internal.R.bool.target_honeycomb_needs_options_menu);
+        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
+
+        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
             addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
         }
         
@@ -2540,8 +2547,10 @@
             if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
                 params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
             }
-            params.dimAmount = a.getFloat(
-                    android.R.styleable.Window_backgroundDimAmount, 0.5f);
+            if (!haveDimAmount()) {
+                params.dimAmount = a.getFloat(
+                        android.R.styleable.Window_backgroundDimAmount, 0.5f);
+            }
         }
 
         if (params.windowAnimations == 0) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ebadb5e..1d5fbc0a 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.IUiModeManager;
+import android.app.ProgressDialog;
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -3078,7 +3079,44 @@
             });
         }
     }
-   
+
+    ProgressDialog mBootMsgDialog = null;
+
+    /** {@inheritDoc} */
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                if (mBootMsgDialog == null) {
+                    mBootMsgDialog = new ProgressDialog(mContext);
+                    mBootMsgDialog.setTitle(R.string.android_upgrading_title);
+                    mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+                    mBootMsgDialog.setIndeterminate(true);
+                    mBootMsgDialog.getWindow().setType(
+                            WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY);
+                    mBootMsgDialog.getWindow().addFlags(
+                            WindowManager.LayoutParams.FLAG_DIM_BEHIND
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
+                    mBootMsgDialog.getWindow().setDimAmount(1);
+                    mBootMsgDialog.setCancelable(false);
+                    mBootMsgDialog.show();
+                }
+                mBootMsgDialog.setMessage(msg);
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    public void hideBootMessages() {
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                if (mBootMsgDialog != null) {
+                    mBootMsgDialog.dismiss();
+                    mBootMsgDialog = null;
+                }
+            }
+        });
+    }
+
     /** {@inheritDoc} */
     public void userActivity() {
         synchronized (mScreenLockTimeout) {
diff --git a/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java
index f968bee..520d302 100644
--- a/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/SimPukUnlockScreen.java
@@ -226,12 +226,6 @@
             mSimUnlockProgressDialog.setCancelable(false);
             mSimUnlockProgressDialog.getWindow().setType(
                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            if (!mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_sf_slowBlur)) {
-                mSimUnlockProgressDialog.getWindow().setFlags(
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-            }
         }
         return mSimUnlockProgressDialog;
     }
diff --git a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
index 8bac969..1acf681 100644
--- a/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java
@@ -196,12 +196,6 @@
             mSimUnlockProgressDialog.setCancelable(false);
             mSimUnlockProgressDialog.getWindow().setType(
                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            if (!mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_sf_slowBlur)) {
-                mSimUnlockProgressDialog.getWindow().setFlags(
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-            }
         }
         return mSimUnlockProgressDialog;
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 941c9c8..744fa50 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -522,6 +522,11 @@
 
 status_t AudioFlinger::setMasterVolume(float value)
 {
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
     // check calling permissions
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
@@ -547,7 +552,10 @@
 
 status_t AudioFlinger::setMode(int mode)
 {
-    status_t ret;
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
 
     // check calling permissions
     if (!settingsAllowed()) {
@@ -577,6 +585,11 @@
 
 status_t AudioFlinger::setMicMute(bool state)
 {
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
     // check calling permissions
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
@@ -584,13 +597,18 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
-    status_t ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state);
+    ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state);
     mHardwareStatus = AUDIO_HW_IDLE;
     return ret;
 }
 
 bool AudioFlinger::getMicMute() const
 {
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return false;
+    }
+
     bool state = AUDIO_MODE_INVALID;
     mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
     mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
@@ -814,6 +832,11 @@
 
 size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
 {
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return 0;
+    }
+
     return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
 }
 
@@ -834,6 +857,11 @@
 
 status_t AudioFlinger::setVoiceVolume(float value)
 {
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
     // check calling permissions
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
@@ -841,7 +869,7 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
-    status_t ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value);
+    ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value);
     mHardwareStatus = AUDIO_HW_IDLE;
 
     return ret;
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index 5c878c9..d37c9ab 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -28,7 +28,6 @@
 import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
-import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -45,14 +44,9 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.zip.GZIPOutputStream;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 73d790a..6b64dd0 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2006-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
@@ -48,7 +47,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -57,7 +55,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
-import android.graphics.BitmapFactory;
 import android.inputmethodservice.InputMethodService;
 import android.os.Binder;
 import android.os.Environment;
@@ -98,12 +95,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.TreeMap;
 
 /**
@@ -147,7 +142,6 @@
     final Handler mHandler;
     final InputMethodSettings mSettings;
     final SettingsObserver mSettingsObserver;
-    final StatusBarManagerService mStatusBar;
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
     private final InputMethodFileManager mFileManager;
@@ -162,10 +156,11 @@
             new LruCache<SuggestionSpan, InputMethodInfo>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
 
     // Ongoing notification
-    private final NotificationManager mNotificationManager;
-    private final KeyguardManager mKeyguardManager;
-    private final Notification mImeSwitcherNotification;
-    private final PendingIntent mImeSwitchPendingIntent;
+    private NotificationManager mNotificationManager;
+    private KeyguardManager mKeyguardManager;
+    private StatusBarManagerService mStatusBar;
+    private Notification mImeSwitcherNotification;
+    private PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
 
@@ -469,8 +464,7 @@
                             // Pick another one...
                             Slog.i(TAG, "Current input method removed: " + curInputMethodId);
                             mImeWindowVis = 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             if (!chooseNewDefaultIMELocked()) {
                                 changed = true;
                                 curIm = null;
@@ -511,7 +505,7 @@
         }
     }
 
-    public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
+    public InputMethodManagerService(Context context) {
         mContext = context;
         mRes = context.getResources();
         mHandler = new Handler(this);
@@ -524,10 +518,6 @@
             }
         });
 
-        mKeyguardManager = (KeyguardManager)
-                mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mNotificationManager = (NotificationManager)
-                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mImeSwitcherNotification = new Notification();
         mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
         mImeSwitcherNotification.when = 0;
@@ -553,8 +543,6 @@
         screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
 
-        mStatusBar = statusBar;
-        statusBar.setIconVisibility("ime", false);
         mNotificationShown = false;
 
         // mSettings should be created before buildInputMethodListLocked
@@ -608,10 +596,17 @@
         }
     }
 
-    public void systemReady() {
+    public void systemReady(StatusBarManagerService statusBar) {
         synchronized (mMethodMap) {
             if (!mSystemReady) {
                 mSystemReady = true;
+                mKeyguardManager = (KeyguardManager)
+                        mContext.getSystemService(Context.KEYGUARD_SERVICE);
+                mNotificationManager = (NotificationManager)
+                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                mStatusBar = statusBar;
+                statusBar.setIconVisibility("ime", false);
+                updateImeWindowStatusLocked();
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
                 try {
@@ -623,6 +618,13 @@
         }
     }
 
+    void updateImeWindowStatusLocked() {
+        if (mStatusBar != null) {
+            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
+                    mBackDisposition);
+        }
+    }
+
     @Override
     public List<InputMethodInfo> getInputMethodList() {
         synchronized (mMethodMap) {
@@ -1009,7 +1011,9 @@
             mEnabledSession = null;
             mCurMethod = null;
         }
-        mStatusBar.setIconVisibility("ime", false);
+        if (mStatusBar != null) {
+            mStatusBar.setIconVisibility("ime", false);
+        }
     }
 
     @Override
@@ -1046,7 +1050,9 @@
             synchronized (mMethodMap) {
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
-                    mStatusBar.setIconVisibility("ime", false);
+                    if (mStatusBar != null) {
+                        mStatusBar.setIconVisibility("ime", false);
+                    }
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
                     CharSequence contentDescription = null;
@@ -1057,9 +1063,12 @@
                     } catch (NameNotFoundException nnfe) {
                         /* ignore */
                     }
-                    mStatusBar.setIcon("ime", packageName, iconId, 0,
-                            contentDescription  != null ? contentDescription.toString() : null);
-                    mStatusBar.setIconVisibility("ime", true);
+                    if (mStatusBar != null) {
+                        mStatusBar.setIcon("ime", packageName, iconId, 0,
+                                contentDescription  != null
+                                        ? contentDescription.toString() : null);
+                        mStatusBar.setIconVisibility("ime", true);
+                    }
                 }
             }
         } finally {
@@ -1125,7 +1134,9 @@
             synchronized (mMethodMap) {
                 mImeWindowVis = vis;
                 mBackDisposition = backDisposition;
-                mStatusBar.setImeWindowStatus(token, vis, backDisposition);
+                if (mStatusBar != null) {
+                    mStatusBar.setImeWindowStatus(token, vis, backDisposition);
+                }
                 final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0;
                 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
                 if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
@@ -1142,12 +1153,14 @@
 
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
-                    mNotificationManager.notify(
-                            com.android.internal.R.string.select_input_method,
-                            mImeSwitcherNotification);
-                    mNotificationShown = true;
+                    if (mNotificationManager != null) {
+                        mNotificationManager.notify(
+                                com.android.internal.R.string.select_input_method,
+                                mImeSwitcherNotification);
+                        mNotificationShown = true;
+                    }
                 } else {
-                    if (mNotificationShown) {
+                    if (mNotificationShown && mNotificationManager != null) {
                         mNotificationManager.cancel(
                                 com.android.internal.R.string.select_input_method);
                         mNotificationShown = false;
@@ -1252,8 +1265,7 @@
                             mImeWindowVis = (mInputShown || hardKeyShown) ? (
                                     InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE)
                                     : 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             // If subtype is null, try to find the most applicable one from
                             // getCurrentInputMethodSubtype.
                             if (subtype == null) {
@@ -1374,13 +1386,12 @@
                             if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
                                     + uid + ": " + client);
                             mImeWindowVis = 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             return false;
                         }
                     } catch (RemoteException e) {
                         mImeWindowVis = 0;
-                        mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
+                        updateImeWindowStatusLocked();
                         return false;
                     }
                 }
@@ -2151,7 +2162,7 @@
                         }
                     });
 
-            if (showSubtypes && !(mKeyguardManager.isKeyguardLocked()
+            if (showSubtypes && mKeyguardManager != null && !(mKeyguardManager.isKeyguardLocked()
                     && mKeyguardManager.isKeyguardSecure())) {
                 mDialogBuilder.setPositiveButton(
                         com.android.internal.R.string.configure_input_methods,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5dd3c5b..e6f92a5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -40,6 +40,7 @@
 import android.server.search.SearchManagerService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 
@@ -66,6 +67,11 @@
 
     ContentResolver mContentResolver;
 
+    void reportWtf(String msg, Throwable e) {
+        Slog.w(TAG, "***********************************************");
+        Log.wtf(TAG, "BOOT FAILURE " + msg, e);
+    }
+
     @Override
     public void run() {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
@@ -116,7 +122,6 @@
         WindowManagerService wm = null;
         BluetoothService bluetooth = null;
         BluetoothA2dpService bluetoothA2dp = null;
-        WiredAccessoryObserver wiredAccessory = null;
         DockObserver dock = null;
         UsbService usb = null;
         UiModeManagerService uiMode = null;
@@ -222,7 +227,8 @@
             }
 
         } catch (RuntimeException e) {
-            Slog.e("System", "Failure starting core service", e);
+            Slog.e("System", "******************************************");
+            Slog.e("System", "************ Failure starting core service", e);
         }
 
         DevicePolicyManagerService devicePolicy = null;
@@ -235,13 +241,52 @@
         CountryDetectorService countryDetector = null;
         TextServicesManagerService tsms = null;
 
+        // Bring up services needed for UI.
+        if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            try {
+                Slog.i(TAG, "Input Method Service");
+                imm = new InputMethodManagerService(context);
+                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
+            } catch (Throwable e) {
+                reportWtf("starting Input Manager Service", e);
+            }
+
+            try {
+                Slog.i(TAG, "Accessibility Manager");
+                ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
+                        new AccessibilityManagerService(context));
+            } catch (Throwable e) {
+                reportWtf("starting Accessibility Manager", e);
+            }
+        }
+
+        try {
+            wm.displayReady();
+        } catch (Throwable e) {
+            reportWtf("making display ready", e);
+        }
+ 
+        try {
+            pm.performBootDexOpt();
+        } catch (Throwable e) {
+            reportWtf("performing boot dexopt", e);
+        }
+
+        try {
+            ActivityManagerNative.getDefault().showBootMessage(
+                    context.getResources().getText(
+                            com.android.internal.R.string.android_upgrading_starting_apps),
+                            false);
+        } catch (RemoteException e) {
+        }
+
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
                 Slog.i(TAG, "Device Policy");
                 devicePolicy = new DevicePolicyManagerService(context);
                 ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DevicePolicyService", e);
+                reportWtf("starting DevicePolicyService", e);
             }
 
             try {
@@ -249,7 +294,7 @@
                 statusBar = new StatusBarManagerService(context, wm);
                 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting StatusBarManagerService", e);
+                reportWtf("starting StatusBarManagerService", e);
             }
 
             try {
@@ -257,15 +302,7 @@
                 ServiceManager.addService(Context.CLIPBOARD_SERVICE,
                         new ClipboardService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Clipboard Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "Input Method Service");
-                imm = new InputMethodManagerService(context, statusBar);
-                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Input Manager Service", e);
+                reportWtf("starting Clipboard Service", e);
             }
 
             try {
@@ -273,7 +310,7 @@
                 networkManagement = NetworkManagementService.create(context);
                 ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkManagement Service", e);
+                reportWtf("starting NetworkManagement Service", e);
             }
 
             try {
@@ -281,7 +318,7 @@
                 tsms = new TextServicesManagerService(context);
                 ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Text Service Manager Service", e);
+                reportWtf("starting Text Service Manager Service", e);
             }
 
             try {
@@ -289,7 +326,7 @@
                 networkStats = new NetworkStatsService(context, networkManagement, alarm);
                 ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkStats Service", e);
+                reportWtf("starting NetworkStats Service", e);
             }
 
             try {
@@ -299,7 +336,7 @@
                         networkStats, networkManagement);
                 ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
+                reportWtf("starting NetworkPolicy Service", e);
             }
 
            try {
@@ -307,7 +344,7 @@
                 wifiP2p = new WifiP2pService(context);
                 ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wi-Fi P2pService", e);
+                reportWtf("starting Wi-Fi P2pService", e);
             }
 
            try {
@@ -316,7 +353,7 @@
                 ServiceManager.addService(Context.WIFI_SERVICE, wifi);
                 wifi.checkAndStartWifi();
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wi-Fi Service", e);
+                reportWtf("starting Wi-Fi Service", e);
             }
 
             try {
@@ -327,7 +364,7 @@
                 networkPolicy.bindConnectivityManager(connectivity);
                 wifiP2p.connectivityServiceReady();
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Connectivity Service", e);
+                reportWtf("starting Connectivity Service", e);
             }
 
             try {
@@ -336,15 +373,7 @@
                 ServiceManager.addService(
                         Context.THROTTLE_SERVICE, throttle);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting ThrottleService", e);
-            }
-
-            try {
-              Slog.i(TAG, "Accessibility Manager");
-              ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
-                      new AccessibilityManagerService(context));
-            } catch (Throwable e) {
-              Slog.e(TAG, "Failure starting Accessibility Manager", e);
+                reportWtf("starting ThrottleService", e);
             }
 
             try {
@@ -355,7 +384,7 @@
                 Slog.i(TAG, "Mount Service");
                 ServiceManager.addService("mount", new MountService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Mount Service", e);
+                reportWtf("starting Mount Service", e);
             }
 
             try {
@@ -364,7 +393,7 @@
                 ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
                 networkPolicy.bindNotificationManager(notification);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Notification Manager", e);
+                reportWtf("starting Notification Manager", e);
             }
 
             try {
@@ -372,7 +401,7 @@
                 ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
                         new DeviceStorageMonitorService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DeviceStorageMonitor service", e);
+                reportWtf("starting DeviceStorageMonitor service", e);
             }
 
             try {
@@ -380,7 +409,7 @@
                 location = new LocationManagerService(context);
                 ServiceManager.addService(Context.LOCATION_SERVICE, location);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Location Manager", e);
+                reportWtf("starting Location Manager", e);
             }
 
             try {
@@ -388,7 +417,7 @@
                 countryDetector = new CountryDetectorService(context);
                 ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Country Detector", e);
+                reportWtf("starting Country Detector", e);
             }
 
             try {
@@ -396,7 +425,7 @@
                 ServiceManager.addService(Context.SEARCH_SERVICE,
                         new SearchManagerService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Search Service", e);
+                reportWtf("starting Search Service", e);
             }
 
             try {
@@ -404,7 +433,7 @@
                 ServiceManager.addService(Context.DROPBOX_SERVICE,
                         new DropBoxManagerService(context, new File("/data/system/dropbox")));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DropBoxManagerService", e);
+                reportWtf("starting DropBoxManagerService", e);
             }
 
             try {
@@ -412,14 +441,14 @@
                 wallpaper = new WallpaperManagerService(context);
                 ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wallpaper Service", e);
+                reportWtf("starting Wallpaper Service", e);
             }
 
             try {
                 Slog.i(TAG, "Audio Service");
                 ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Audio Service", e);
+                reportWtf("starting Audio Service", e);
             }
 
             try {
@@ -427,15 +456,15 @@
                 // Listen for dock station changes
                 dock = new DockObserver(context, power);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DockObserver", e);
+                reportWtf("starting DockObserver", e);
             }
 
             try {
                 Slog.i(TAG, "Wired Accessory Observer");
                 // Listen for wired headset changes
-                wiredAccessory = new WiredAccessoryObserver(context);
+                new WiredAccessoryObserver(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting WiredAccessoryObserver", e);
+                reportWtf("starting WiredAccessoryObserver", e);
             }
 
             try {
@@ -444,7 +473,7 @@
                 usb = new UsbService(context);
                 ServiceManager.addService(Context.USB_SERVICE, usb);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting UsbService", e);
+                reportWtf("starting UsbService", e);
             }
 
             try {
@@ -452,7 +481,7 @@
                 // Listen for UI mode changes
                 uiMode = new UiModeManagerService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting UiModeManagerService", e);
+                reportWtf("starting UiModeManagerService", e);
             }
 
             try {
@@ -468,21 +497,21 @@
                 appWidget = new AppWidgetService(context);
                 ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting AppWidget Service", e);
+                reportWtf("starting AppWidget Service", e);
             }
 
             try {
                 Slog.i(TAG, "Recognition Service");
                 recognition = new RecognitionManagerService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Recognition Service", e);
+                reportWtf("starting Recognition Service", e);
             }
 
             try {
                 Slog.i(TAG, "DiskStats Service");
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DiskStats Service", e);
+                reportWtf("starting DiskStats Service", e);
             }
 
             try {
@@ -494,14 +523,14 @@
                 ServiceManager.addService("samplingprofiler",
                             new SamplingProfilerService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting SamplingProfiler Service", e);
+                reportWtf("starting SamplingProfiler Service", e);
             }
 
             try {
                 Slog.i(TAG, "NetworkTimeUpdateService");
                 networkTimeUpdater = new NetworkTimeUpdateService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkTimeUpdate service");
+                reportWtf("starting NetworkTimeUpdate service", e);
             }
         }
 
@@ -522,14 +551,26 @@
         // It is now time to start up the app processes...
 
         if (devicePolicy != null) {
-            devicePolicy.systemReady();
+            try {
+                devicePolicy.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making Device Policy Service ready", e);
+            }
         }
 
         if (notification != null) {
-            notification.systemReady();
+            try {
+                notification.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making Notification Service ready", e);
+            }
         }
 
-        wm.systemReady();
+        try {
+            wm.systemReady();
+        } catch (Throwable e) {
+            reportWtf("making Window Manager Service ready", e);
+        }
 
         if (safeMode) {
             ActivityManagerService.self().showSafeModeOverlay();
@@ -547,7 +588,8 @@
         power.systemReady();
         try {
             pm.systemReady();
-        } catch (RemoteException e) {
+        } catch (Throwable e) {
+            reportWtf("making Package Manager Service ready", e);
         }
 
         // These are needed to propagate to the runnable below.
@@ -569,6 +611,7 @@
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
         final TextServicesManagerService textServiceManagerServiceF = tsms;
+        final StatusBarManagerService statusBarF = statusBar;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -581,28 +624,96 @@
                 Slog.i(TAG, "Making services ready");
 
                 startSystemUi(contextF);
-                if (batteryF != null) batteryF.systemReady();
-                if (networkManagementF != null) networkManagementF.systemReady();
-                if (networkStatsF != null) networkStatsF.systemReady();
-                if (networkPolicyF != null) networkPolicyF.systemReady();
-                if (connectivityF != null) connectivityF.systemReady();
-                if (dockF != null) dockF.systemReady();
-                if (usbF != null) usbF.systemReady();
-                if (uiModeF != null) uiModeF.systemReady();
-                if (recognitionF != null) recognitionF.systemReady();
+                try {
+                    if (batteryF != null) batteryF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Battery Service ready", e);
+                }
+                try {
+                    if (networkManagementF != null) networkManagementF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Managment Service ready", e);
+                }
+                try {
+                    if (networkStatsF != null) networkStatsF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Stats Service ready", e);
+                }
+                try {
+                    if (networkPolicyF != null) networkPolicyF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Policy Service ready", e);
+                }
+                try {
+                    if (connectivityF != null) connectivityF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Connectivity Service ready", e);
+                }
+                try {
+                    if (dockF != null) dockF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Dock Service ready", e);
+                }
+                try {
+                    if (usbF != null) usbF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making USB Service ready", e);
+                }
+                try {
+                    if (uiModeF != null) uiModeF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making UI Mode Service ready", e);
+                }
+                try {
+                    if (recognitionF != null) recognitionF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Recognition Service ready", e);
+                }
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
                 // third party code...
 
-                if (appWidgetF != null) appWidgetF.systemReady(safeMode);
-                if (wallpaperF != null) wallpaperF.systemReady();
-                if (immF != null) immF.systemReady();
-                if (locationF != null) locationF.systemReady();
-                if (countryDetectorF != null) countryDetectorF.systemReady();
-                if (throttleF != null) throttleF.systemReady();
-                if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
-                if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+                try {
+                    if (appWidgetF != null) appWidgetF.systemReady(safeMode);
+                } catch (Throwable e) {
+                    reportWtf("making App Widget Service ready", e);
+                }
+                try {
+                    if (wallpaperF != null) wallpaperF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Wallpaper Service ready", e);
+                }
+                try {
+                    if (immF != null) immF.systemReady(statusBarF);
+                } catch (Throwable e) {
+                    reportWtf("making Input Method Service ready", e);
+                }
+                try {
+                    if (locationF != null) locationF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Location Service ready", e);
+                }
+                try {
+                    if (countryDetectorF != null) countryDetectorF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Country Detector Service ready", e);
+                }
+                try {
+                    if (throttleF != null) throttleF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Throttle Service ready", e);
+                }
+                try {
+                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Time Service ready", e);
+                }
+                try {
+                    if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Text Services Manager Service ready", e);
+                }
             }
         });
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 800c4fc..b817598 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -91,6 +91,7 @@
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IPermissionController;
 import android.os.Looper;
@@ -3748,6 +3749,10 @@
         mWindowManager.enableScreenAfterBoot();
     }
 
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        mWindowManager.showBootMessage(msg, always);
+    }
+
     final void finishBooting() {
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -6446,7 +6451,9 @@
         File fname = new File(systemDir, "called_pre_boots.dat");
         return fname;
     }
-    
+
+    static final int LAST_DONE_VERSION = 10000;
+
     private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
         ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
         File file = getCalledPreBootReceiversFile();
@@ -6454,16 +6461,21 @@
         try {
             fis = new FileInputStream(file);
             DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
-            int vers = dis.readInt();
-            String codename = dis.readUTF();
-            if (vers == android.os.Build.VERSION.SDK_INT
-                    && codename.equals(android.os.Build.VERSION.CODENAME)) {
-                int num = dis.readInt();
-                while (num > 0) {
-                    num--;
-                    String pkg = dis.readUTF();
-                    String cls = dis.readUTF();
-                    lastDoneReceivers.add(new ComponentName(pkg, cls));
+            int fvers = dis.readInt();
+            if (fvers == LAST_DONE_VERSION) {
+                String vers = dis.readUTF();
+                String codename = dis.readUTF();
+                String build = dis.readUTF();
+                if (android.os.Build.VERSION.RELEASE.equals(vers)
+                        && android.os.Build.VERSION.CODENAME.equals(codename)
+                        && android.os.Build.VERSION.INCREMENTAL.equals(build)) {
+                    int num = dis.readInt();
+                    while (num > 0) {
+                        num--;
+                        String pkg = dis.readUTF();
+                        String cls = dis.readUTF();
+                        lastDoneReceivers.add(new ComponentName(pkg, cls));
+                    }
                 }
             }
         } catch (FileNotFoundException e) {
@@ -6488,8 +6500,10 @@
             Slog.i(TAG, "Writing new set of last done pre-boot receivers...");
             fos = new FileOutputStream(file);
             dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
-            dos.writeInt(android.os.Build.VERSION.SDK_INT);
+            dos.writeInt(LAST_DONE_VERSION);
+            dos.writeUTF(android.os.Build.VERSION.RELEASE);
             dos.writeUTF(android.os.Build.VERSION.CODENAME);
+            dos.writeUTF(android.os.Build.VERSION.INCREMENTAL);
             dos.writeInt(list.size());
             for (int i=0; i<list.size(); i++) {
                 dos.writeUTF(list.get(i).getPackageName());
@@ -6571,6 +6585,9 @@
                                                 mDidUpdate = true;
                                             }
                                             writeLastDonePreBootReceivers(doneReceivers);
+                                            showBootMessage(mContext.getText(
+                                                    R.string.android_upgrading_complete),
+                                                    false);
                                             systemReady(goingCallback);
                                         }
                                     });
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index dbb8164..2f19a46 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -187,6 +187,7 @@
     static final int SCAN_NEW_INSTALL = 1<<4;
     static final int SCAN_NO_PATHS = 1<<5;
     static final int SCAN_UPDATE_TIME = 1<<6;
+    static final int SCAN_DEFER_DEX = 1<<7;
 
     static final int REMOVE_CHATTY = 1<<16;
 
@@ -349,6 +350,9 @@
     /** List of packages waiting for verification. */
     final SparseArray<InstallArgs> mPendingVerification = new SparseArray<InstallArgs>();
 
+    final ArrayList<PackageParser.Package> mDeferredDexOpt =
+            new ArrayList<PackageParser.Package>();
+
     /** Token for keys in mPendingVerification. */
     private int mPendingVerificationToken = 0;
 
@@ -907,7 +911,7 @@
 
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
-            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
+            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;
             if (mNoDexOpt) {
                 Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                 scanMode |= SCAN_NO_DEX;
@@ -2899,6 +2903,33 @@
         }
     }
 
+    public void performBootDexOpt() {
+        ArrayList<PackageParser.Package> pkgs = null;
+        synchronized (mPackages) {
+            if (mDeferredDexOpt.size() > 0) {
+                pkgs = new ArrayList<PackageParser.Package>(mDeferredDexOpt);
+                mDeferredDexOpt.clear();
+            }
+        }
+        if (pkgs != null) {
+            for (int i=0; i<pkgs.size(); i++) {
+                try {
+                    ActivityManagerNative.getDefault().showBootMessage(
+                            mContext.getResources().getString(
+                                    com.android.internal.R.string.android_upgrading_apk,
+                                    i+1, pkgs.size()), true);
+                } catch (RemoteException e) {
+                }
+                PackageParser.Package p = pkgs.get(i);
+                synchronized (mInstallLock) {
+                    if (!p.mDidDexOpt) {
+                        performDexOptLI(p, false, false);
+                    }
+                }
+            }
+        }
+    }
+
     public boolean performDexOpt(String packageName) {
         enforceSystemOrRoot("Only the system can request dexopt be performed");
 
@@ -2914,25 +2945,32 @@
             }
         }
         synchronized (mInstallLock) {
-            return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
+            return performDexOptLI(p, false, false) == DEX_OPT_PERFORMED;
         }
     }
 
     static final int DEX_OPT_SKIPPED = 0;
     static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_DEFERRED = 2;
     static final int DEX_OPT_FAILED = -1;
 
-    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer) {
         boolean performed = false;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             String path = pkg.mScanPath;
             int ret = 0;
             try {
                 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
-                    ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
-                            !isForwardLocked(pkg));
-                    pkg.mDidDexOpt = true;
-                    performed = true;
+                    if (!forceDex && defer) {
+                        mDeferredDexOpt.add(pkg);
+                        return DEX_OPT_DEFERRED;
+                    } else {
+                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+                        ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
+                                !isForwardLocked(pkg));
+                        pkg.mDidDexOpt = true;
+                        performed = true;
+                    }
                 }
             } catch (FileNotFoundException e) {
                 Slog.w(TAG, "Apk not found for dexopt: " + path);
@@ -3487,7 +3525,8 @@
         pkg.mScanPath = path;
 
         if ((scanMode&SCAN_NO_DEX) == 0) {
-            if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
+            if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0)
+                    == DEX_OPT_FAILED) {
                 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                 return null;
             }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8fd4f95..dc5555e 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,7 @@
 import android.Manifest;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.ProgressDialog;
 import android.app.StatusBarManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -407,6 +408,7 @@
     boolean mSafeMode;
     boolean mDisplayEnabled = false;
     boolean mSystemBooted = false;
+    boolean mShowingBootMessages = false;
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
     int mBaseDisplayWidth = 0;
@@ -4685,16 +4687,17 @@
                 return;
             }
             mSystemBooted = true;
+            hideBootMessagesLocked();
         }
 
         performEnableScreen();
     }
 
-    public void enableScreenIfNeededLocked() {
+    void enableScreenIfNeededLocked() {
         if (mDisplayEnabled) {
             return;
         }
-        if (!mSystemBooted) {
+        if (!mSystemBooted && !mShowingBootMessages) {
             return;
         }
         mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
@@ -4705,7 +4708,7 @@
             if (mDisplayEnabled) {
                 return;
             }
-            if (!mSystemBooted) {
+            if (!mSystemBooted && !mShowingBootMessages) {
                 return;
             }
 
@@ -4749,6 +4752,33 @@
                 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
     }
 
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        boolean first = false;
+        synchronized(mWindowMap) {
+            if (!mShowingBootMessages) {
+                if (!always) {
+                    return;
+                }
+                first = true;
+            }
+            if (mSystemBooted) {
+                return;
+            }
+            mShowingBootMessages = true;
+            mPolicy.showBootMessage(msg, always);
+        }
+        if (first) {
+            performEnableScreen();
+        }
+    }
+
+    public void hideBootMessagesLocked() {
+        if (mShowingBootMessages) {
+            mShowingBootMessages = false;
+            mPolicy.hideBootMessages();
+        }
+    }
+
     public void setInTouchMode(boolean mode) {
         synchronized(mWindowMap) {
             mInTouchMode = mode;
@@ -6136,7 +6166,7 @@
         return mSafeMode;
     }
 
-    public void systemReady() {
+    public void displayReady() {
         synchronized(mWindowMap) {
             if (mDisplay != null) {
                 throw new IllegalStateException("Display already initialized");
@@ -6165,14 +6195,16 @@
             mActivityManager.updateConfiguration(null);
         } catch (RemoteException e) {
         }
-
-        mPolicy.systemReady();
-
+        
         synchronized (mWindowMap) {
             readForcedDisplaySizeLocked();
         }
     }
 
+    public void systemReady() {
+        mPolicy.systemReady();
+    }
+
     // This is an animation that does nothing: it just immediately finishes
     // itself every time it is called.  It is used as a stub animation in cases
     // where we want to synchronize multiple things that may be animating.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 50afb3d..1f27a70 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -822,7 +822,7 @@
         hwc_layer_t* const cur(hwc.getLayers());
         for (size_t i=0 ; cur && i<count ; i++) {
             currentLayers[i]->setGeometry(&cur[i]);
-            if (mDebugDisableHWC) {
+            if (mDebugDisableHWC || mDebugRegion) {
                 cur[i].compositionType = HWC_FRAMEBUFFER;
                 cur[i].flags |= HWC_SKIP_LAYER;
             }
@@ -974,6 +974,10 @@
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t flags = hw.getFlags();
+    const int32_t height = hw.getHeight();
+    if (mInvalidRegion.isEmpty()) {
+        return;
+    }
 
     if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
             (flags & DisplayHardware::BUFFER_PRESERVED))) {
@@ -999,26 +1003,21 @@
     while (it != end) {
         const Rect& r = *it++;
         GLfloat vertices[][2] = {
-                { r.left,  r.top },
-                { r.left,  r.bottom },
-                { r.right, r.bottom },
-                { r.right, r.top }
+                { r.left,  height - r.top },
+                { r.left,  height - r.bottom },
+                { r.right, height - r.bottom },
+                { r.right, height - r.top }
         };
         glVertexPointer(2, GL_FLOAT, 0, vertices);
         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     }
 
-    if (mInvalidRegion.isEmpty()) {
-        mDirtyRegion.dump("mDirtyRegion");
-        mInvalidRegion.dump("mInvalidRegion");
-    }
     hw.flip(mInvalidRegion);
 
     if (mDebugRegion > 1)
         usleep(mDebugRegion * 1000);
 
     glEnable(GL_SCISSOR_TEST);
-    //mDirtyRegion.dump("mDirtyRegion");
 }
 
 void SurfaceFlinger::drawWormhole() const
@@ -1581,7 +1580,7 @@
         HWComposer& hwc(hw.getHwComposer());
         snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
                 hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                mDebugDisableHWC ? "disabled" : "enabled");
+                (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
         result.append(buffer);
         hwc.dump(result, buffer, SIZE);
 
@@ -1660,21 +1659,15 @@
             case 1002:  // SHOW_UPDATES
                 n = data.readInt32();
                 mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
+                invalidateHwcGeometry();
+                repaintEverything();
                 return NO_ERROR;
             case 1003:  // SHOW_BACKGROUND
                 n = data.readInt32();
                 mDebugBackground = n ? 1 : 0;
                 return NO_ERROR;
-            case 1008:  // toggle use of hw composer
-                n = data.readInt32();
-                mDebugDisableHWC = n ? 1 : 0;
-                invalidateHwcGeometry();
-                // fall-through...
             case 1004:{ // repaint everything
-                Mutex::Autolock _l(mStateLock);
-                const DisplayHardware& hw(graphicPlane(0).displayHardware());
-                mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
-                signalEvent();
+                repaintEverything();
                 return NO_ERROR;
             }
             case 1005:{ // force transaction
@@ -1690,6 +1683,12 @@
                 mFreezeCount = data.readInt32();
                 mFreezeDisplayTime = 0;
                 return NO_ERROR;
+            case 1008:  // toggle use of hw composer
+                n = data.readInt32();
+                mDebugDisableHWC = n ? 1 : 0;
+                invalidateHwcGeometry();
+                repaintEverything();
+                return NO_ERROR;
             case 1010:  // interrogate.
                 reply->writeInt32(0);
                 reply->writeInt32(0);
@@ -1707,6 +1706,13 @@
     return err;
 }
 
+void SurfaceFlinger::repaintEverything() {
+    Mutex::Autolock _l(mStateLock);
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
+    signalEvent();
+}
+
 // ---------------------------------------------------------------------------
 
 status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1738238..d68e484 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -278,6 +278,7 @@
             void        handleRepaint();
             void        postFramebuffer();
             void        composeSurfaces(const Region& dirty);
+            void        repaintEverything();
 
 
             ssize_t     addClientLayer(const sp<Client>& client,