Merge "More adjustments to permissions." into jb-mr1-dev
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 05b04dc..7606d5e3 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5010,7 +5010,21 @@
         if (TextUtils.isEmpty(parentName)) {
             return null;
         }
-        return new Intent().setClassName(this, parentName);
+
+        // If the parent itself has no parent, generate a main activity intent.
+        final ComponentName target = new ComponentName(this, parentName);
+        try {
+            final ActivityInfo parentInfo = getPackageManager().getActivityInfo(target, 0);
+            final String parentActivity = parentInfo.parentActivityName;
+            final Intent parentIntent = parentActivity == null
+                    ? Intent.makeMainActivity(target)
+                    : new Intent().setComponent(target);
+            return parentIntent;
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "getParentActivityIntent: bad parentActivityName '" + parentName +
+                    "' in manifest");
+            return null;
+        }
     }
 
     // ------------------ Internal API ------------------
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index f21b3fd..9c83362 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -124,24 +124,12 @@
      * @return This TaskStackBuilder for method chaining
      */
     public TaskStackBuilder addParentStack(Activity sourceActivity) {
-        final int insertAt = mIntents.size();
-        Intent parent = sourceActivity.getParentActivityIntent();
-        PackageManager pm = sourceActivity.getPackageManager();
-        while (parent != null) {
-            mIntents.add(insertAt, parent);
-            try {
-                ActivityInfo info = pm.getActivityInfo(parent.getComponent(), 0);
-                String parentActivity = info.parentActivityName;
-                if (parentActivity != null) {
-                    parent = new Intent().setComponent(
-                            new ComponentName(mSourceContext, parentActivity));
-                } else {
-                    parent = null;
-                }
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
-                throw new IllegalArgumentException(e);
-            }
+        final Intent parent = sourceActivity.getParentActivityIntent();
+        if (parent != null) {
+            // We have the actual parent intent, build the rest from static metadata
+            // then add the direct parent intent to the end.
+            addParentStack(parent.getComponent());
+            addNextIntent(parent);
         }
         return this;
     }
@@ -155,24 +143,7 @@
      * @return This TaskStackBuilder for method chaining
      */
     public TaskStackBuilder addParentStack(Class<?> sourceActivityClass) {
-        final int insertAt = mIntents.size();
-        PackageManager pm = mSourceContext.getPackageManager();
-        try {
-            ActivityInfo info = pm.getActivityInfo(
-                    new ComponentName(mSourceContext, sourceActivityClass), 0);
-            String parentActivity = info.parentActivityName;
-            while (parentActivity != null) {
-                Intent parent = new Intent().setComponent(
-                        new ComponentName(mSourceContext, parentActivity));
-                mIntents.add(insertAt, parent);
-                info = pm.getActivityInfo(parent.getComponent(), 0);
-                parentActivity = info.parentActivityName;
-            }
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
-            throw new IllegalArgumentException(e);
-        }
-        return this;
+        return addParentStack(new ComponentName(mSourceContext, sourceActivityClass));
     }
 
     /**
@@ -191,11 +162,13 @@
             ActivityInfo info = pm.getActivityInfo(sourceActivityName, 0);
             String parentActivity = info.parentActivityName;
             while (parentActivity != null) {
-                Intent parent = new Intent().setComponent(
-                        new ComponentName(info.packageName, parentActivity));
-                mIntents.add(insertAt, parent);
-                info = pm.getActivityInfo(parent.getComponent(), 0);
+                final ComponentName target = new ComponentName(mSourceContext, parentActivity);
+                info = pm.getActivityInfo(target, 0);
                 parentActivity = info.parentActivityName;
+                final Intent parent = parentActivity == null && insertAt == 0
+                        ? Intent.makeMainActivity(target)
+                        : new Intent().setComponent(target);
+                mIntents.add(insertAt, parent);
             }
         } catch (NameNotFoundException e) {
             Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f3dbecb..a182234 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3236,7 +3236,7 @@
         public static final String DISPLAY_DENSITY_FORCED = Global.DISPLAY_DENSITY_FORCED;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Global#ASSISTED_GPS_ENABLE} instead
+         * @deprecated Use {@link android.provider.Settings.Global#ASSISTED_GPS_ENABLED} instead
          * @hide
          */
         @Deprecated
@@ -4345,21 +4345,18 @@
                 "sync_max_retry_delay_in_seconds";
 
         /**
-         * The interval in milliseconds at which to check the number of SMS sent
-         * out without asking for use permit, to limit the un-authorized SMS
-         * usage.
+         * @deprecated Use {@link Settings.Global#SMS_OUTGOING_CHECK_INTERVAL_MS} instead.
          * @hide
          */
         public static final String SMS_OUTGOING_CHECK_INTERVAL_MS =
-                "sms_outgoing_check_interval_ms";
+                Global.SMS_OUTGOING_CHECK_INTERVAL_MS;
 
         /**
-         * The number of outgoing SMS sent without asking for user permit
-         * (of {@link #SMS_OUTGOING_CHECK_INTERVAL_MS}
+         * @deprecated Use {@link Settings.Global#SMS_OUTGOING_CHECK_MAX_COUNT} instead.
          * @hide
          */
         public static final String SMS_OUTGOING_CHECK_MAX_COUNT =
-                "sms_outgoing_check_max_count";
+                Global.SMS_OUTGOING_CHECK_MAX_COUNT;
 
         /**
          * The global search provider chosen by the user (if multiple global
@@ -4861,13 +4858,6 @@
                 "contacts_preauth_uri_expiration";
 
         /**
-         * Prefix for SMS short code regex patterns (country code is appended).
-         * @see com.android.internal.telephony.SmsUsageMonitor
-         * @hide
-         */
-        public static final String SMS_SHORT_CODES_PREFIX = "sms_short_codes_";
-
-        /**
          * Overlay display devices setting.
          * The associated value is a specially formatted string that describes the
          * size and density of simulated secondary display devices.
@@ -5341,6 +5331,13 @@
         * {@hide} */
        public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
 
+       /** Show package verification setting in the Settings app.
+        * 1 = show (default)
+        * 0 = hide
+        * {@hide}
+        */
+       public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible";
+
        /**
         * The interval in milliseconds at which to check packet counts on the
         * mobile data interface when screen is on, to detect possible data
@@ -5427,6 +5424,38 @@
                "setup_prepaid_detection_redir_host";
 
        /**
+        * The interval in milliseconds at which to check the number of SMS sent out without asking
+        * for use permit, to limit the un-authorized SMS usage.
+        *
+        * @hide
+        */
+       public static final String SMS_OUTGOING_CHECK_INTERVAL_MS =
+               "sms_outgoing_check_interval_ms";
+
+       /**
+        * The number of outgoing SMS sent without asking for user permit (of {@link
+        * #SMS_OUTGOING_CHECK_INTERVAL_MS}
+        *
+        * @hide
+        */
+       public static final String SMS_OUTGOING_CHECK_MAX_COUNT =
+               "sms_outgoing_check_max_count";
+
+       /**
+        * Used to disable SMS short code confirmation - defaults to true.
+        * @see com.android.internal.telephony.SmsUsageMonitor
+        * @hide
+        */
+       public static final String SMS_SHORT_CODE_CONFIRMATION = "sms_short_code_confirmation";
+
+       /**
+        * Prefix for SMS short code regex patterns (country code is appended).
+        * @see com.android.internal.telephony.SmsUsageMonitor
+        * @hide
+        */
+       public static final String SMS_SHORT_CODES_PREFIX = "sms_short_codes_";
+
+       /**
         * Used to disable Tethering on a device - defaults to true
         * @hide
         */
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index bcb8800..fa03139 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -137,6 +137,7 @@
     private long mPrevTime;
     private boolean mInProgress;
     private int mSpanSlop;
+    private int mMinSpan;
 
     /**
      * Consistency verifier for debugging purposes.
@@ -149,6 +150,8 @@
         mContext = context;
         mListener = listener;
         mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
+        mMinSpan = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.config_minScalingSpan);
     }
 
     /**
@@ -209,8 +212,11 @@
         float devSumX = 0, devSumY = 0;
         for (int i = 0; i < count; i++) {
             if (skipIndex == i) continue;
-            devSumX += Math.abs(event.getX(i) - focusX);
-            devSumY += Math.abs(event.getY(i) - focusY);
+
+            // Average touch major and touch minor and convert the resulting diameter into a radius.
+            final float touchSize = (event.getTouchMajor(i) + event.getTouchMinor(i)) / 4;
+            devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
+            devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
         }
         final float devX = devSumX / div;
         final float devY = devSumY / div;
@@ -228,7 +234,7 @@
         final boolean wasInProgress = mInProgress;
         mFocusX = focusX;
         mFocusY = focusY;
-        if (mInProgress && (span == 0 || configChanged)) {
+        if (mInProgress && (span < mMinSpan || configChanged)) {
             mListener.onScaleEnd(this);
             mInProgress = false;
             mInitialSpan = span;
@@ -238,7 +244,7 @@
             mPrevSpanY = mCurrSpanY = spanY;
             mInitialSpan = mPrevSpan = mCurrSpan = span;
         }
-        if (!mInProgress && span != 0 &&
+        if (!mInProgress && span >= mMinSpan &&
                 (wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
             mPrevSpanX = mCurrSpanX = spanX;
             mPrevSpanY = mCurrSpanY = spanY;
diff --git a/core/res/res/anim/screen_user_enter.xml b/core/res/res/anim/screen_user_enter.xml
index a73dea3..cb0a634 100644
--- a/core/res/res/anim/screen_user_enter.xml
+++ b/core/res/res/anim/screen_user_enter.xml
@@ -17,9 +17,6 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="100%p" android:toXDelta="0"
-            android:duration="500"
-            android:interpolator="@interpolator/decelerate_quad" />
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
             android:duration="500"
             android:interpolator="@interpolator/decelerate_quad" />
diff --git a/core/res/res/anim/screen_user_exit.xml b/core/res/res/anim/screen_user_exit.xml
index ec94b76..3d465be 100644
--- a/core/res/res/anim/screen_user_exit.xml
+++ b/core/res/res/anim/screen_user_exit.xml
@@ -17,9 +17,6 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android">
-    <translate android:fromXDelta="0" android:toXDelta="-100%p"
-            android:duration="500"
-            android:interpolator="@interpolator/decelerate_quad" />
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:duration="500"
             android:interpolator="@interpolator/decelerate_quad" />
diff --git a/core/res/res/drawable-hdpi/panel_bg_holo_dark.9.png b/core/res/res/drawable-hdpi/panel_bg_holo_dark.9.png
index 1b4fed8..a5ac279 100644
--- a/core/res/res/drawable-hdpi/panel_bg_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/panel_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/panel_bg_holo_light.9.png b/core/res/res/drawable-hdpi/panel_bg_holo_light.9.png
index c8b3177..583865e 100644
--- a/core/res/res/drawable-hdpi/panel_bg_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/panel_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/panel_bg_holo_dark.9.png b/core/res/res/drawable-mdpi/panel_bg_holo_dark.9.png
index 8c51b01..588eb3c 100644
--- a/core/res/res/drawable-mdpi/panel_bg_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/panel_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/panel_bg_holo_light.9.png b/core/res/res/drawable-mdpi/panel_bg_holo_light.9.png
index f4a25bc..c1cdbc7 100644
--- a/core/res/res/drawable-mdpi/panel_bg_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/panel_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/panel_bg_holo_dark.9.png b/core/res/res/drawable-xhdpi/panel_bg_holo_dark.9.png
index 0cf7ac8..aaf6d8b 100644
--- a/core/res/res/drawable-xhdpi/panel_bg_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/panel_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/panel_bg_holo_light.9.png b/core/res/res/drawable-xhdpi/panel_bg_holo_light.9.png
index 9bdf3f1..6ea7615 100644
--- a/core/res/res/drawable-xhdpi/panel_bg_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/panel_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/kg_avatar_overlay.xml b/core/res/res/drawable/kg_avatar_overlay.xml
new file mode 100644
index 0000000..781c1df
--- /dev/null
+++ b/core/res/res/drawable/kg_avatar_overlay.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+        android:drawable="@drawable/activity_picker_bg_activated" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
index 9999177..23f9b6d 100644
--- a/core/res/res/layout/keyguard_multi_user_avatar.xml
+++ b/core/res/res/layout/keyguard_multi_user_avatar.xml
@@ -23,9 +23,11 @@
     android:layout_width="125dp"
     android:layout_height="125dp"
     android:background="#550000ff"
-    android:gravity="center_horizontal">
+    android:gravity="center_horizontal"
+    android:foreground="@drawable/kg_avatar_overlay">
     <ImageView
         android:id="@+id/keyguard_user_avatar"
+        android:scaleType="centerCrop"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"/>
diff --git a/core/res/res/layout/keyguard_multi_user_selector.xml b/core/res/res/layout/keyguard_multi_user_selector.xml
index 3ed9103..c599fd5dd 100644
--- a/core/res/res/layout/keyguard_multi_user_selector.xml
+++ b/core/res/res/layout/keyguard_multi_user_selector.xml
@@ -19,23 +19,15 @@
 <com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
-    android:layout_width="375dp"
-    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:layout_gravity="center">
 
-    <include
-        android:id="@+id/keyguard_active_user"
-        android:layout_width="250dp"
-        android:layout_height="250dp"
-        layout="@layout/keyguard_multi_user_avatar"/>
+    <com.android.internal.policy.impl.keyguard.KeyguardSubdivisionLayout
+        android:id="@+id/keyguard_users_grid"
+        android:orientation="horizontal"
+        android:layout_width="300dp"
+        android:layout_height="300dp"
+        android:layout_gravity="center" />
 
-    <ScrollView
-        android:layout_width="125dp"
-        android:layout_height="250dp">
-        <LinearLayout
-            android:id="@+id/keyguard_inactive_users"
-            android:orientation="vertical"
-            layout_width="match_parent"
-            layout_height="wrap_content"/>
-    </ScrollView>
 </com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView>
\ No newline at end of file
diff --git a/core/res/res/layout/sms_short_code_confirmation_dialog.xml b/core/res/res/layout/sms_short_code_confirmation_dialog.xml
new file mode 100644
index 0000000..ed08375
--- /dev/null
+++ b/core/res/res/layout/sms_short_code_confirmation_dialog.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="8dip"
+    android:layout_marginRight="8dip"
+    android:orientation="vertical">
+
+    <TextView android:id="@+id/sms_short_code_confirm_message"
+        style="?android:attr/textAppearanceMedium"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip"
+        android:paddingTop="8dip"
+        android:paddingBottom="8dip"/>
+
+    <LinearLayout android:id="@+id/sms_short_code_detail_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center_vertical"
+        android:minHeight="@dimen/alert_dialog_title_height"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip">
+        <ImageView android:id="@+id/sms_short_code_coins_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingRight="8dip"
+            android:src="@null" />
+        <TextView android:id="@+id/sms_short_code_detail_message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+
+    <CheckBox android:id="@+id/sms_short_code_remember_choice_checkbox"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sms_short_code_remember_choice" />
+</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7895489..93d7fcc 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -925,4 +925,16 @@
 
     <!--  Maximum number of supported users -->
     <integer name="config_multiuserMaximumUsers">1</integer>
+
+    <!-- Minimum span needed to begin a touch scaling gesture.
+         If the span is equal to or greater than this size, a scaling gesture
+         will begin, where supported. (See android.view.ScaleGestureDetector)
+
+         This also takes into account the size of any active touch points.
+         Devices with screens that deviate too far from their assigned density
+         bucket should consider tuning this value in a device-specific overlay.
+         For best results, care should be taken such that this value remains
+         larger than the minimum reported touchMajor/touchMinor values
+         reported by the hardware. -->
+    <dimen name="config_minScalingSpan">25mm</dimen>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dcb2ff2..73a61b6 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1258,26 +1258,26 @@
       such as GPS or location providers.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessFineLocation">precise (GPS) location</string>
+    <string name="permlab_accessFineLocation">precise location (GPS and
+      network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessFineLocation" product="tablet">Access precise
-      location sources such as the Global Positioning System on the tablet. When
-      location services are available and turned on, this permission allows the
-      app to determine your precise location.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessFineLocation" product="default">Access precise
-      location sources such as the Global Positioning System on the phone. When
-      location services are available and turned on, this permission allows the
-      app to determine your precise location.</string>
+    <string name="permdesc_accessFineLocation">Allows the app to get your
+      precise location using the Global Positioning System (GPS) or network
+      location sources such as cell towers and Wi-Fi. These location services
+      must be turned on and available to your device for the app to use them.
+      Apps may use this to determine where you are, and may consume additional
+      battery power.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessCoarseLocation">approximate (network-based) location</string>
+    <string name="permlab_accessCoarseLocation">approximate location
+      (network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessCoarseLocation">Access
-      approximate location from location providers using network sources such as
-      cell tower and Wi-Fi. When these location services are available and turned
-      on, this permission allows the app to determine your approximate
-      location.</string>
+    <string name="permdesc_accessCoarseLocation">Allows the app to get your
+      approximate location. This location is derived by location services using
+      network location sources such as cell towers and Wi-Fi. These location
+      services must be turned on and available to your device for the app to
+      use them. Apps may use this to determine approximately where you
+      are.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessSurfaceFlinger">access SurfaceFlinger</string>
@@ -3092,20 +3092,22 @@
     <string name="sms_control_no">Deny</string>
 
     <!-- SMS short code verification dialog. --> <skip />
-    <!-- The dialog title for the SMS short code confirmation dialog. [CHAR LIMIT=30] -->
-    <string name="sms_short_code_confirm_title">Send SMS to short code?</string>
-    <!-- The dialog title for the SMS premium short code confirmation dialog. [CHAR LIMIT=30] -->
-    <string name="sms_premium_short_code_confirm_title">Send premium SMS?</string>
     <!-- The message text for the SMS short code confirmation dialog. [CHAR LIMIT=NONE] -->
-    <string name="sms_short_code_confirm_message">&lt;b><xliff:g id="app_name">%1$s</xliff:g>&lt;/b> would like to send a text message to &lt;b><xliff:g id="dest_address">%2$s</xliff:g>&lt;/b>, which appears to be an SMS short code.&lt;p>Sending text messages to some short codes may cause your mobile account to be billed for premium services.&lt;p>Do you want to allow this app to send the message?</string>
-    <!-- The message text for the SMS short code confirmation dialog. [CHAR LIMIT=NONE] -->
-    <string name="sms_premium_short_code_confirm_message">&lt;b><xliff:g id="app_name">%1$s</xliff:g>&lt;/b> would like to send a text message to &lt;b><xliff:g id="dest_address">%2$s</xliff:g>&lt;/b>, which is a premium SMS short code.&lt;p>&lt;b>Sending a message to this destination will cause your mobile account to be billed for premium services.&lt;/b>&lt;p>Do you want to allow this app to send the message?</string>
-    <!-- Text of the approval button for the SMS short code confirmation dialog. [CHAR LIMIT=50] -->
-    <string name="sms_short_code_confirm_allow">Send message</string>
+    <string name="sms_short_code_confirm_message">&lt;b><xliff:g id="app_name">%1$s</xliff:g>&lt;/b> would like to send a message to &lt;b><xliff:g id="dest_address">%2$s</xliff:g>&lt;/b>.</string>
+    <!-- Message details for the SMS short code confirmation dialog (possible premium short code). [CHAR LIMIT=NONE] -->
+    <string name="sms_short_code_details">This may cause charges on your mobile account.</string>
+    <!-- Message details for the SMS short code confirmation dialog (premium short code). [CHAR LIMIT=NONE] -->
+    <string name="sms_premium_short_code_details">This will cause charges on your mobile account.</string>
+    <!-- Text of the approval button for the SMS short code confirmation dialog. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_allow">Send</string>
     <!-- Text of the cancel button for the SMS short code confirmation dialog. [CHAR LIMIT=30] -->
-    <string name="sms_short_code_confirm_deny">Don\'t send</string>
-    <!-- Text of the button for the SMS short code confirmation dialog to report a malicious app. [CHAR LIMIT=30] -->
-    <string name="sms_short_code_confirm_report">Report malicious app</string>
+    <string name="sms_short_code_confirm_deny">Cancel</string>
+    <!-- Text of the checkbox for the SMS short code confirmation dialog to remember the user's choice. [CHAR LIMIT=40] -->
+    <string name="sms_short_code_remember_choice">Remember my choice</string>
+    <!-- Text of the approval button for the SMS short code confirmation dialog when checkbox is checked. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_always_allow">Always Allow</string>
+    <!-- Text of the cancel button for the SMS short code confirmation dialog when checkbox is checked. [CHAR LIMIT=30] -->
+    <string name="sms_short_code_confirm_never_allow">Never Allow</string>
 
     <!-- SIM swap and device reboot Dialog --> <skip />
     <!-- See SIM_REMOVED_DIALOG.  This is the title of that dialog. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b9a1d64..2bfb06d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -211,6 +211,10 @@
   <java-symbol type="id" name="status_bar_latest_event_content" />
   <java-symbol type="id" name="action_divider" />
   <java-symbol type="id" name="overflow_divider" />
+  <java-symbol type="id" name="sms_short_code_confirm_message" />
+  <java-symbol type="id" name="sms_short_code_detail_layout" />
+  <java-symbol type="id" name="sms_short_code_detail_message" />
+  <java-symbol type="id" name="sms_short_code_remember_choice_checkbox" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -739,13 +743,13 @@
   <java-symbol type="string" name="sms_control_title" />
   <java-symbol type="string" name="sms_control_no" />
   <java-symbol type="string" name="sms_control_yes" />
-  <java-symbol type="string" name="sms_premium_short_code_confirm_message" />
-  <java-symbol type="string" name="sms_premium_short_code_confirm_title" />
   <java-symbol type="string" name="sms_short_code_confirm_allow" />
   <java-symbol type="string" name="sms_short_code_confirm_deny" />
+  <java-symbol type="string" name="sms_short_code_confirm_always_allow" />
+  <java-symbol type="string" name="sms_short_code_confirm_never_allow" />
   <java-symbol type="string" name="sms_short_code_confirm_message" />
-  <java-symbol type="string" name="sms_short_code_confirm_report" />
-  <java-symbol type="string" name="sms_short_code_confirm_title" />
+  <java-symbol type="string" name="sms_short_code_details" />
+  <java-symbol type="string" name="sms_premium_short_code_details" />
   <java-symbol type="string" name="submit" />
   <java-symbol type="string" name="sync_binding_label" />
   <java-symbol type="string" name="sync_do_nothing" />
@@ -1052,6 +1056,7 @@
   <java-symbol type="layout" name="notification_template_inbox" />
   <java-symbol type="layout" name="keyguard_multi_user_avatar" />
   <java-symbol type="layout" name="keyguard_multi_user_selector_widget" />
+  <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
@@ -1113,6 +1118,8 @@
   <java-symbol type="layout" name="media_route_list_item_collapse_group" />
   <java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
 
+  <java-symbol type="dimen" name="config_minScalingSpan" />
+
   <!-- From android.policy -->
   <java-symbol type="anim" name="app_starting_exit" />
   <java-symbol type="anim" name="lock_screen_behind_enter" />
@@ -1254,10 +1261,9 @@
   <java-symbol type="id" name="pin_delete_button" />
   <java-symbol type="id" name="keyguard_user_avatar" />
   <java-symbol type="id" name="keyguard_user_name" />
-  <java-symbol type="id" name="keyguard_active_user" />
-  <java-symbol type="id" name="keyguard_inactive_users" />
   <java-symbol type="id" name="keyguard_transport_control" />
   <java-symbol type="id" name="keyguard_status_view" />
+  <java-symbol type="id" name="keyguard_users_grid" />
   <java-symbol type="integer" name="config_carDockRotation" />
   <java-symbol type="integer" name="config_defaultUiModeType" />
   <java-symbol type="integer" name="config_deskDockRotation" />
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.mk b/core/tests/coretests/apks/install_bad_dex/Android.mk
new file mode 100644
index 0000000..769a1b0
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_bad_dex
+
+LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/classes.dex
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
new file mode 100644
index 0000000..fe4dd8e
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.coretests.install_loc">
+
+    <application android:hasCode="true">
+        <activity
+            android:name="com.android.frameworks.coretests.TestActivity">
+        </activity>
+    </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install_bad_dex/classes.dex b/core/tests/coretests/apks/install_bad_dex/classes.dex
new file mode 100644
index 0000000..284b6d4
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/classes.dex
@@ -0,0 +1 @@
+This is a bad dex
diff --git a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
new file mode 100644
index 0000000..3b8b3b1
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string name="dummy">dummy</string>
+</resources>
diff --git a/core/tests/coretests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java b/core/tests/coretests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java
new file mode 100644
index 0000000..10d0551
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * 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 com.android.frameworks.coretests;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+
+}
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index de2993a..b61ea8e 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -23,6 +23,6 @@
     libnativehelper
 
 LOCAL_MODULE := libframeworks_coretests_jni
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 785842f..5881aa1 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -39,6 +39,7 @@
 import android.os.ServiceManager;
 import android.os.StatFs;
 import android.os.SystemClock;
+import android.os.UserManager;
 import android.os.storage.IMountService;
 import android.os.storage.StorageListener;
 import android.os.storage.StorageManager;
@@ -562,6 +563,14 @@
             fail(pkgName + " shouldnt be installed");
         } catch (NameNotFoundException e) {
         }
+
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        List<UserInfo> users = um.getUsers();
+        for (UserInfo user : users) {
+            String dataDir = PackageManager.getDataDirForUser(user.id, pkgName);
+            assertFalse("Application data directory should not exist: " + dataDir,
+                    new File(dataDir).exists());
+        }
     }
 
     class InstallParams {
@@ -707,9 +716,7 @@
                         PackageManager.GET_UNINSTALLED_PACKAGES);
                 GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
                 invokeDeletePackage(pkg.packageName, 0, receiver);
-            } catch (NameNotFoundException e1) {
-            } catch (Exception e) {
-                failStr(e);
+            } catch (NameNotFoundException e) {
             }
         }
         try {
@@ -3476,6 +3483,12 @@
         assertNotNull("signatures should not be null", packageInfo.signatures);
     }
 
+    public void testInstall_BadDex_CleanUp() throws Exception {
+        int retCode = PackageManager.INSTALL_FAILED_DEXOPT;
+        installFromRawResource("install.apk", R.raw.install_bad_dex, 0, true, true, retCode,
+                PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+    }
+
     /*---------- Recommended install location tests ----*/
     /*
      * TODO's
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index e85a23c..80d7728 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -32,6 +32,6 @@
 LOCAL_MODULE:= librs_jni
 LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
 LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS
+LOCAL_REQUIRED_MODULES := libRS libRSDriver
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 95f8500..8fe28a3 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -86,6 +86,11 @@
         void show();
     }
 
+    /*package*/ interface UserSwitcherCallback {
+        void hideSecurityView(int duration);
+        void showSecurityView();
+    }
+
     public KeyguardHostView(Context context) {
         this(context, null);
     }
@@ -348,6 +353,7 @@
                 (failedAttemptsBeforeWipe - failedAttempts)
                 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
 
+        boolean showTimeout = false;
         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
             // If we reach this code, it means the user has installed a DevicePolicyManager
             // that requests device wipe after N attempts.  Once we get below the grace
@@ -361,7 +367,7 @@
                 showWipeDialog(failedAttempts);
             }
         } else {
-            boolean showTimeout =
+            showTimeout =
                 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
             if (usingPattern && mEnableFallback) {
                 if (failedAttempts == failedAttemptWarning) {
@@ -374,12 +380,12 @@
                     showTimeout = false;
                 }
             }
-            if (showTimeout) {
-                showTimeoutDialog();
-            }
         }
         monitor.reportFailedUnlockAttempt();
         mLockPatternUtils.reportFailedPasswordAttempt();
+        if (showTimeout) {
+            showTimeoutDialog();
+        }
     }
 
     /**
@@ -690,11 +696,27 @@
         List<UserInfo> users = mUm.getUsers();
 
         if (users.size() > 1) {
-            KeyguardWidgetFrame userswitcher = (KeyguardWidgetFrame)
+            KeyguardWidgetFrame userSwitcher = (KeyguardWidgetFrame)
                 LayoutInflater.from(mContext).inflate(R.layout.keyguard_multi_user_selector_widget,
                         mAppWidgetContainer, false);
-            // add the switcher to the left of status view
-            mAppWidgetContainer.addView(userswitcher, getWidgetPosition(R.id.keyguard_status_view));
+
+            // add the switcher in the first position
+            mAppWidgetContainer.addView(userSwitcher, getWidgetPosition(R.id.keyguard_status_view));
+            KeyguardMultiUserSelectorView multiUser = (KeyguardMultiUserSelectorView)
+                    userSwitcher.getChildAt(0);
+
+            UserSwitcherCallback callback = new UserSwitcherCallback() {
+                @Override
+                public void hideSecurityView(int duration) {
+                    mSecurityViewContainer.animate().alpha(0).setDuration(duration);
+                }
+
+                @Override
+                public void showSecurityView() {
+                    mSecurityViewContainer.setAlpha(1.0f);
+                }
+            };
+            multiUser.setCallback(callback);
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
index 8aef68f..759068d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
@@ -16,16 +16,17 @@
 
 package com.android.internal.policy.impl.keyguard;
 
-import android.app.ActivityManagerNative;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManagerGlobal;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -33,11 +34,15 @@
 import com.android.internal.R;
 
 class KeyguardMultiUserAvatar extends FrameLayout {
-    private static final String TAG = "KeyguardViewHost";
 
     private ImageView mUserImage;
     private TextView mUserName;
     private UserInfo mUserInfo;
+    private static final int INACTIVE_COLOR = 85;
+    private static final int INACTIVE_ALPHA = 195;
+    private static final float ACTIVE_SCALE = 1.1f;
+    private boolean mActive;
+    private boolean mInit = true;
     private KeyguardMultiUserSelectorView mUserSelector;
 
     public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
@@ -73,17 +78,86 @@
 
         mUserImage.setImageDrawable(Drawable.createFromPath(mUserInfo.iconPath));
         mUserName.setText(mUserInfo.name);
-        setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                try {
-                    ActivityManagerNative.getDefault().switchUser(mUserInfo.id);
-                    WindowManagerGlobal.getWindowManagerService().lockNow();
-                    mUserSelector.init();
-                } catch (RemoteException re) {
-                    Log.e(TAG, "Couldn't switch user " + re);
+        setOnClickListener(mUserSelector);
+        setActive(false, false, 0, null);
+        mInit = false;
+    }
+
+    public void setActive(boolean active, boolean animate, int duration, final Runnable onComplete) {
+        if (mActive != active || mInit) {
+            mActive = active;
+            final int finalFilterAlpha = mActive ? 0 : INACTIVE_ALPHA;
+            final int initFilterAlpha = mActive ? INACTIVE_ALPHA : 0;
+
+            final float finalScale = mActive ? ACTIVE_SCALE : 1.0f;
+            final float initScale = mActive ? 1.0f : ACTIVE_SCALE;
+
+            if (active) {
+                KeyguardSubdivisionLayout parent = (KeyguardSubdivisionLayout) getParent();
+                parent.setTopChild(parent.indexOfChild(this));
+            }
+
+            if (animate) {
+                ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+                va.addUpdateListener(new AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        float r = animation.getAnimatedFraction();
+                        float scale = (1 - r) * initScale + r * finalScale;
+                        int filterAlpha = (int) ((1 - r) * initFilterAlpha + r * finalFilterAlpha);
+                        setScaleX(scale);
+                        setScaleY(scale);
+                        mUserImage.setColorFilter(Color.argb(filterAlpha, INACTIVE_COLOR,
+                                INACTIVE_COLOR, INACTIVE_COLOR));
+                        mUserSelector.invalidate();
+
+                    }
+                });
+                va.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (onComplete != null) {
+                            onComplete.run();
+                        }
+                    }
+                });
+                va.setDuration(duration);
+                va.start();
+            } else {
+                setScaleX(finalScale);
+                setScaleY(finalScale);
+                mUserImage.setColorFilter(Color.argb(finalFilterAlpha, INACTIVE_COLOR,
+                        INACTIVE_COLOR, INACTIVE_COLOR));
+                if (onComplete != null) {
+                    post(onComplete);
                 }
             }
+        }
+    }
+
+    boolean mLockDrawableState = false;
+
+    public void lockDrawableState() {
+        mLockDrawableState = true;
+    }
+
+    public void resetDrawableState() {
+        mLockDrawableState = false;
+        post(new Runnable() {
+            @Override
+            public void run() {
+                refreshDrawableState();
+            }
         });
     }
+
+    protected void drawableStateChanged() {
+        if (!mLockDrawableState) {
+            super.drawableStateChanged();
+        }
+    }
+
+    public UserInfo getUserInfo() {
+        return mUserInfo;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
index ba99a55..01d5d8c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
@@ -22,15 +22,26 @@
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.util.AttributeSet;
-import android.widget.LinearLayout;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+import android.widget.FrameLayout;
 
 import com.android.internal.R;
+import com.android.internal.policy.impl.keyguard.KeyguardHostView.UserSwitcherCallback;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 
-public class KeyguardMultiUserSelectorView extends LinearLayout{
-    private KeyguardMultiUserAvatar mActiveUser;
-    private LinearLayout mInactiveUsers;
+public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener {
+    private static final String TAG = "KeyguardMultiUserSelectorView";
+
+    private KeyguardSubdivisionLayout mUsersGrid;
+    private KeyguardMultiUserAvatar mActiveUserAvatar;
+    private UserSwitcherCallback mCallback;
+    private static final int SWITCH_ANIMATION_DURATION = 150;
+    private static final int FADE_OUT_ANIMATION_DURATION = 100;
 
     public KeyguardMultiUserSelectorView(Context context) {
         this(context, null, 0);
@@ -48,37 +59,77 @@
         init();
     }
 
+    public void setCallback(UserSwitcherCallback callback) {
+        mCallback = callback;
+    }
+
     public void init() {
-        mActiveUser = (KeyguardMultiUserAvatar) findViewById(R.id.keyguard_active_user);
-        mInactiveUsers = (LinearLayout) findViewById(R.id.keyguard_inactive_users);
+        mUsersGrid = (KeyguardSubdivisionLayout) findViewById(R.id.keyguard_users_grid);
+        mUsersGrid.removeAllViews();
+        setClipChildren(false);
+        setClipToPadding(false);
 
-        mInactiveUsers.removeAllViews();
-
-        UserInfo currentUser;
+        UserInfo activeUser;
         try {
-            currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+            activeUser = ActivityManagerNative.getDefault().getCurrentUser();
         } catch (RemoteException re) {
-            currentUser = null;
+            activeUser = null;
         }
 
         UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUm.getUsers());
+        Collections.sort(users, mOrderAddedComparator);
+
         for (UserInfo user: users) {
-            if (user.id == currentUser.id) {
-                setActiveUser(user);
-            } else {
-                createAndAddInactiveUser(user);
+            KeyguardMultiUserAvatar uv = createAndAddUser(user);
+            if (user.id == activeUser.id) {
+                mActiveUserAvatar = uv;
             }
         }
+        mActiveUserAvatar.setActive(true, false, 0, null);
     }
 
-    private void setActiveUser(UserInfo user) {
-        mActiveUser.setup(user, this);
-    }
+    Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() {
+        @Override
+        public int compare(UserInfo lhs, UserInfo rhs) {
+            return (lhs.serialNumber - rhs.serialNumber);
+        }
+    };
 
-    private void createAndAddInactiveUser(UserInfo user) {
+    private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) {
         KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
                 R.layout.keyguard_multi_user_avatar, mContext, this, user);
-        mInactiveUsers.addView(uv);
+        mUsersGrid.addView(uv);
+        return uv;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (!(v instanceof KeyguardMultiUserAvatar)) return;
+        final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v;
+        if (mActiveUserAvatar == avatar) {
+            // They clicked the active user, no need to do anything
+            return;
+        } else {
+            // Reset the previously active user to appear inactive
+            avatar.lockDrawableState();
+            mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION);
+            mActiveUserAvatar.setActive(false, true,  SWITCH_ANIMATION_DURATION, new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        ActivityManagerNative.getDefault().switchUser(avatar.getUserInfo().id);
+                        WindowManagerGlobal.getWindowManagerService().lockNow();
+                        // Set the new active user, and make it appear active
+                        avatar.resetDrawableState();
+                        mCallback.showSecurityView();
+                        mActiveUserAvatar = avatar;
+                        mActiveUserAvatar.setActive(true, false, 0, null);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Couldn't switch user " + re);
+                    }
+                }
+            });
+        }
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index 7e9aa43..01f7af3 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -97,11 +97,17 @@
         if (deadline != 0) {
             handleAttemptLockout(deadline);
         } else {
-            mNavigationManager.setMessage(
-                    mIsAlpha ? R.string.kg_password_instructions : R.string.kg_pin_instructions);
+            resetState();
         }
     }
 
+    private void resetState() {
+        mNavigationManager.setMessage(
+                mIsAlpha ? R.string.kg_password_instructions : R.string.kg_pin_instructions);
+        mPasswordEntry.setEnabled(true);
+        mKeyboardView.setEnabled(true);
+    }
+
     @Override
     protected void onFinishInflate() {
         mLockPatternUtils = new LockPatternUtils(mContext); // TODO: use common one
@@ -297,8 +303,7 @@
 
             @Override
             public void onFinish() {
-                mPasswordEntry.setEnabled(true);
-                mKeyboardView.setEnabled(true);
+                resetState();
             }
         }.start();
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index e325f94..8d83484 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -54,7 +54,7 @@
     private static final int BATTERY_INFO = 15;
 
     private StatusMode mStatus;
-    private String mDateFormatString;
+    private CharSequence mDateFormatString;
 
     // Views that this class controls.
     // NOTE: These may be null in some LockScreen screens and should protect from NPE
@@ -101,7 +101,8 @@
     public KeyguardStatusViewManager(View view) {
         if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()");
         mContainer = view;
-        mDateFormatString = getContext().getString(R.string.abbrev_wday_month_day_no_year);
+        mDateFormatString = getContext().getResources()
+            .getText(R.string.abbrev_wday_month_day_no_year);
         mLockPatternUtils = new LockPatternUtils(view.getContext());
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(view.getContext());
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSubdivisionLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSubdivisionLayout.java
new file mode 100644
index 0000000..b7d94a9
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSubdivisionLayout.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.policy.impl.keyguard;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * A layout that arranges its children into a special type of grid.
+ */
+public class KeyguardSubdivisionLayout extends ViewGroup {
+    ArrayList<BiTree> mCells = new ArrayList<BiTree>();
+    int mNumChildren = -1;
+    int mWidth = -1;
+    int mHeight = -1;
+    int mTopChild = 0;
+
+    public KeyguardSubdivisionLayout(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardSubdivisionLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardSubdivisionLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setClipChildren(false);
+        setClipToPadding(false);
+        setChildrenDrawingOrderEnabled(true);
+    }
+
+    private class BiTree {
+        Rect rect;
+        BiTree left;
+        BiTree right;
+        int nodeDepth;
+        ArrayList<BiTree> leafs;
+
+        public BiTree(Rect r) {
+            rect = r;
+        }
+
+        public BiTree() {
+        }
+
+        boolean isLeaf() {
+            return (left == null) && (right == null);
+        }
+
+        int depth() {
+            if (left != null && right != null) {
+                return Math.max(left.depth(), right.depth()) + 1;
+            } else if (left != null) {
+                return left.depth() + 1;
+            } else if (right != null) {
+                return right.depth() + 1;
+            } else {
+                return 1;
+            }
+        }
+
+        int numLeafs() {
+            if (left != null && right != null) {
+                return left.numLeafs() + right.numLeafs();
+            } else if (left != null) {
+                return left.numLeafs();
+            } else if (right != null) {
+                return right.numLeafs();
+            } else {
+                return 1;
+            }
+        }
+
+        BiTree getNextNodeToBranch() {
+            if (leafs == null) {
+                leafs = new ArrayList<BiTree>();
+            }
+            leafs.clear();
+            getLeafs(leafs, 1);
+
+            // We find the first leaf who's depth is not
+            double r = log2(leafs.size());
+            if (Math.ceil(r) == Math.floor(r)) {
+                return leafs.get(leafs.size() - 1);
+            }
+
+            int treeDepth = depth();
+            for (int i = leafs.size() - 1; i >= 0; i--) {
+                BiTree n = leafs.get(i);
+                if (n.nodeDepth < treeDepth) {
+                    return n;
+                }
+            }
+            return null;
+        }
+
+        // Gets leafs in left to right order
+        void getLeafs(ArrayList<BiTree> leafs, int depth) {
+            if (isLeaf()) {
+                this.nodeDepth = depth;
+                leafs.add(this);
+            } else {
+                if (left != null) {
+                    left.getLeafs(leafs, depth + 1);
+                }
+                if (right != null) {
+                    right.getLeafs(leafs, depth + 1);
+                }
+            }
+        }
+    }
+
+    double log2(double d) {
+        return Math.log(d) / Math.log(2);
+    }
+
+    private void addCell(BiTree tree) {
+        BiTree branch = tree.getNextNodeToBranch();
+        Rect r = branch.rect;
+        branch.left = new BiTree();
+        branch.right = new BiTree();
+        int newDepth = tree.depth();
+
+        // For each level of the tree, we alternate between horizontal and vertical division
+        if (newDepth % 2 == 0) {
+            // Divide the cell vertically
+            branch.left.rect = new Rect(r.left, r.top, r.right, r.top + r.height() / 2);
+            branch.right.rect = new Rect(r.left, r.top + r.height() / 2, r.right, r.bottom);
+        } else {
+            // Divide the cell horizontally
+            branch.left.rect = new Rect(r.left, r.top, r.left + r.width() / 2, r.bottom);
+            branch.right.rect = new Rect(r.left + r.width() / 2, r.top, r.right, r.bottom);
+        }
+    }
+
+    private void constructGrid(int width, int height, int numChildren) {
+        mCells.clear();
+        BiTree root = new BiTree(new Rect(0, 0, width, height));
+
+        // We add nodes systematically until the number of leafs matches the number of children
+        while (root.numLeafs() < numChildren) {
+            addCell(root);
+        }
+
+        // Spit out the final list of cells
+        root.getLeafs(mCells, 1);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height =  MeasureSpec.getSize(heightMeasureSpec);
+        int childCount = getChildCount();
+
+        if (mNumChildren != childCount || width != getMeasuredWidth() ||
+                height != getMeasuredHeight()) {
+            constructGrid(width, height, childCount);
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            Rect rect = mCells.get(i).rect;
+            child.measure(MeasureSpec.makeMeasureSpec(rect.width(), MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(rect.height(), MeasureSpec.EXACTLY));
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            Rect rect = mCells.get(i).rect;
+            child.layout(rect.left, rect.top, rect.right, rect.bottom);
+        }
+    }
+
+    public void setTopChild(int top) {
+        mTopChild = top;
+        invalidate();
+    }
+
+    protected int getChildDrawingOrder(int childCount, int i) {
+        int ret = i;
+        if (i == childCount - 1) {
+            ret = mTopChild;
+        } else if (i >= mTopChild){
+            ret = i + 1;
+        }
+        return ret;
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5c3af79..68ac38a 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -55,6 +56,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -834,7 +836,11 @@
      */
     public List<ScanResult> getScanResults() {
         enforceAccessPermission();
-        return mWifiStateMachine.syncGetScanResultsList();
+        if (UserHandle.getCallingUserId() != ActivityManager.getCurrentUser()) {
+            return new ArrayList<ScanResult>();
+        } else {
+            return mWifiStateMachine.syncGetScanResultsList();
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 2ef1f9e..ce52d2b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -215,7 +215,7 @@
     /**
      * Whether verification is enabled by default.
      */
-    private static final boolean DEFAULT_VERIFY_ENABLE = false;
+    private static final boolean DEFAULT_VERIFY_ENABLE = true;
 
     /**
      * The default maximum time to wait for the verification agent to return in
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index 3524a08..1bd7811 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -239,6 +239,7 @@
     private void apply() {
         if (mDirty != 0) {
             if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
+                mScreenBrightnessModulator.setBrightness(0, true /*sync*/);
                 PowerManagerService.nativeSetScreenState(false);
             }
 
@@ -246,15 +247,16 @@
                 mElectronBeam.draw(mElectronBeamLevel);
             }
 
-            if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0) {
-                mScreenBrightnessModulator.setBrightness(mScreenOn ?
-                        (int)(mScreenBrightness * mElectronBeamLevel) : 0);
-            }
-
             if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
                 PowerManagerService.nativeSetScreenState(true);
             }
 
+            if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0
+                    && mScreenOn) {
+                mScreenBrightnessModulator.setBrightness(
+                        (int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/);
+            }
+
             mDirty = 0;
 
             if (mCleanListener != null) {
diff --git a/services/java/com/android/server/power/PhotonicModulator.java b/services/java/com/android/server/power/PhotonicModulator.java
index f7c9c7d..c9b5d90 100644
--- a/services/java/com/android/server/power/PhotonicModulator.java
+++ b/services/java/com/android/server/power/PhotonicModulator.java
@@ -49,11 +49,12 @@
     }
 
     /**
-     * Asynchronously sets the backlight brightness.
+     * Sets the backlight brightness, synchronously or asynchronously.
      *
      * @param lightValue The new light value, from 0 to 255.
+     * @param sync If true, waits for the brightness change to complete before returning.
      */
-    public void setBrightness(int lightValue) {
+    public void setBrightness(int lightValue, boolean sync) {
         synchronized (mLock) {
             if (lightValue != mPendingLightValue) {
                 mPendingLightValue = lightValue;
@@ -63,6 +64,15 @@
                     mExecutor.execute(mTask);
                 }
             }
+            if (sync) {
+                while (mPendingChange) {
+                    try {
+                        mLock.wait();
+                    } catch (InterruptedException ex) {
+                        // ignore it
+                    }
+                }
+            }
         }
     }
 
@@ -76,6 +86,7 @@
                     if (newLightValue == mActualLightValue) {
                         mSuspendBlocker.release();
                         mPendingChange = false;
+                        mLock.notifyAll();
                         return;
                     }
                     mActualLightValue = newLightValue;
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index c6b7e0d..2445b98 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -4,6 +4,7 @@
 
 import android.graphics.Matrix;
 import android.util.Slog;
+import android.view.Display;
 import android.view.Surface;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
@@ -134,11 +135,13 @@
         thumbnailTransformation.clear();
         thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
         thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
-        final boolean screenAnimation = mAnimator.mScreenRotationAnimation != null
-                && mAnimator.mScreenRotationAnimation.isAnimating();
+
+        ScreenRotationAnimation screenRotationAnimation =
+                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
+        final boolean screenAnimation = screenRotationAnimation != null
+                && screenRotationAnimation.isAnimating();
         if (screenAnimation) {
-            thumbnailTransformation.postCompose(
-                    mAnimator.mScreenRotationAnimation.getEnterTransformation());
+            thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
         }
         // cache often used attributes locally
         final float tmpFloats[] = mService.mTmpFloats;
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 87a2880..9bca834 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -219,5 +219,13 @@
             mDimHeight = o.mDimHeight;
             mDimTarget = o.mDimTarget;
         }
+
+        public void printTo(String prefix, PrintWriter pw) {
+            pw.print(prefix);
+            pw.print("mDimWinAnimator="); pw.print(mDimWinAnimator.mWin.mAttrs.getTitle());
+                    pw.print(" "); pw.print(mDimWidth); pw.print(" x ");
+                    pw.print(mDimHeight);
+            pw.print(" mDimTarget="); pw.println(mDimTarget);
+        }
     }
 }
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index d1742ff..3898ebc 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -101,31 +101,32 @@
         mDisplay.getDisplayInfo(mDisplayInfo);
     }
 
-    public void dump(PrintWriter pw) {
-        pw.print("  Display: mDisplayId="); pw.println(mDisplayId);
-        pw.print("  init="); pw.print(mInitialDisplayWidth); pw.print("x");
-        pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
-        pw.print("dpi");
-        if (mInitialDisplayWidth != mBaseDisplayWidth
-                || mInitialDisplayHeight != mBaseDisplayHeight
-                || mInitialDisplayDensity != mBaseDisplayDensity) {
-            pw.print(" base=");
-            pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
-            pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
-        }
-        pw.print(" cur=");
-        pw.print(mDisplayInfo.logicalWidth);
-        pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
-        pw.print(" app=");
-        pw.print(mDisplayInfo.appWidth);
-        pw.print("x"); pw.print(mDisplayInfo.appHeight);
-        pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
-        pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
-        pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
-        pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-        pw.print("  layoutNeeded="); pw.println(layoutNeeded);
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
+        final String subPrefix = "  " + prefix;
+        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
+            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
+            pw.print("dpi");
+            if (mInitialDisplayWidth != mBaseDisplayWidth
+                    || mInitialDisplayHeight != mBaseDisplayHeight
+                    || mInitialDisplayDensity != mBaseDisplayDensity) {
+                pw.print(" base=");
+                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
+            }
+            pw.print(" cur=");
+            pw.print(mDisplayInfo.logicalWidth);
+            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
+            pw.print(" app=");
+            pw.print(mDisplayInfo.appWidth);
+            pw.print("x"); pw.print(mDisplayInfo.appHeight);
+            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
+            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
+            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
+            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+        pw.print(subPrefix); pw.print("layoutNeeded="); pw.print(layoutNeeded);
         if (mMagnificationSpec != null) {
-            pw.print("  mMagnificationSpec="); pw.println(mMagnificationSpec);
+            pw.print(" mMagnificationSpec="); pw.print(mMagnificationSpec);
         }
         pw.println();
     }
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index cabe611..4494058 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -16,6 +16,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Surface;
@@ -39,8 +40,6 @@
     final Context mContext;
     final WindowManagerPolicy mPolicy;
 
-    ArrayList<WinAnimatorList> mWinAnimatorLists = new ArrayList<WinAnimatorList>();
-
     boolean mAnimating;
 
     final Runnable mAnimationRunnable;
@@ -64,24 +63,19 @@
      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
     private int mAnimTransactionSequence;
 
-    /** The one and only screen rotation if one is happening */
-    ScreenRotationAnimation mScreenRotationAnimation = null;
-
     // Window currently running an animation that has requested it be detached
     // from the wallpaper.  This means we need to ensure the wallpaper is
     // visible behind it in case it animates in a way that would allow it to be
     // seen. If multiple windows satisfy this, use the lowest window.
     WindowState mWindowDetachedWallpaper = null;
 
-    DimSurface mWindowAnimationBackgroundSurface = null;
-
     WindowStateAnimator mUniverseBackground = null;
     int mAboveUniverseLayer = 0;
 
     int mBulkUpdateParams = 0;
 
-    DimAnimator mDimAnimator = null;
-    DimAnimator.Parameters mDimParams = null;
+    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
+            new SparseArray<WindowAnimator.DisplayContentsAnimator>();
 
     static final int WALLPAPER_ACTION_PENDING = 1;
     int mPendingActions;
@@ -127,11 +121,18 @@
         };
     }
 
-    void initializeLocked(final int layerStack) {
-        mWindowAnimationBackgroundSurface =
-                new DimSurface(mService.mFxSession, layerStack);
-        mDimAnimator = new DimAnimator(mService.mFxSession, layerStack);
-        mInitialized = true;
+    void addDisplayLocked(final int displayId) {
+        DisplayContentsAnimator displayAnimator = getDisplayContentsAnimatorLocked(displayId);
+        displayAnimator.mWindowAnimationBackgroundSurface =
+                new DimSurface(mService.mFxSession, displayId);
+        displayAnimator.mDimAnimator = new DimAnimator(mService.mFxSession, displayId);
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            mInitialized = true;
+        }
+    }
+
+    void removeDisplayLocked(final int displayId) {
+        mDisplayContentsAnimators.delete(displayId);
     }
 
     /** Locked on mAnimToLayout */
@@ -165,8 +166,6 @@
                 mWallpaperTokens = new ArrayList<WindowToken>(layoutToAnim.mWallpaperTokens);
             }
 
-            mWinAnimatorLists =
-                    new ArrayList<WinAnimatorList>(layoutToAnim.mWinAnimatorLists);
             mWallpaperTarget = layoutToAnim.mWallpaperTarget;
             mWpAppAnimator = mWallpaperTarget == null
                     ? null : mWallpaperTarget.mAppToken == null
@@ -175,20 +174,34 @@
             mUpperWallpaperTarget = layoutToAnim.mUpperWallpaperTarget;
 
             // Set the new DimAnimator params.
-            DimAnimator.Parameters dimParams = layoutToAnim.mDimParams;
-            if (dimParams == null) {
-                mDimParams = null;
-            } else {
-                final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
+            final int numDisplays = mDisplayContentsAnimators.size();
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
-                // Only set dim params on the highest dimmed layer.
-                final WindowStateAnimator existingDimWinAnimator = mDimParams == null
-                        ? null : mDimParams.mDimWinAnimator;
-                // Don't turn on for an unshown surface, or for any layer but the highest dimmed one.
-                if (newWinAnimator.mSurfaceShown &&
-                        (existingDimWinAnimator == null || !existingDimWinAnimator.mSurfaceShown
-                        || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-                    mDimParams = new DimAnimator.Parameters(dimParams);
+                displayAnimator.mWinAnimators.clear();
+                final WinAnimatorList winAnimators = layoutToAnim.mWinAnimatorLists.get(displayId);
+                if (winAnimators != null) {
+                    displayAnimator.mWinAnimators.addAll(winAnimators);
+                }
+
+                DimAnimator.Parameters dimParams = layoutToAnim.mDimParams.get(displayId);
+                if (dimParams == null) {
+                    displayAnimator.mDimParams = null;
+                } else {
+                    final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
+
+                    // Only set dim params on the highest dimmed layer.
+                    final WindowStateAnimator existingDimWinAnimator =
+                            displayAnimator.mDimParams == null ?
+                                    null : displayAnimator.mDimParams.mDimWinAnimator;
+                    // Don't turn on for an unshown surface, or for any layer but the highest
+                    // dimmed layer.
+                    if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
+                            || !existingDimWinAnimator.mSurfaceShown
+                            || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+                        displayAnimator.mDimParams = new DimAnimator.Parameters(dimParams);
+                    }
                 }
             }
 
@@ -225,7 +238,7 @@
         }
     }
 
-    private void updateWindowsAppsAndRotationAnimationsLocked() {
+    private void updateAppWindowsLocked() {
         int i;
         final int NAT = mAppAnimators.size();
         for (i=0; i<NAT; i++) {
@@ -258,21 +271,13 @@
                         "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
             }
         }
-
-        if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
-            if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
-                mAnimating = true;
-            } else {
-                mBulkUpdateParams |= SET_UPDATE_ROTATION;
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
-            }
-        }
     }
 
-    private void updateWindowsLocked(final WinAnimatorList winAnimatorList) {
+    private void updateWindowsLocked(final int displayId) {
         ++mAnimTransactionSequence;
 
+        final WinAnimatorList winAnimatorList =
+                getDisplayContentsAnimatorLocked(displayId).mWinAnimators;
         ArrayList<WindowStateAnimator> unForceHiding = null;
         boolean wallpaperInUnForceHiding = false;
 
@@ -313,7 +318,6 @@
                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                                 "Animation started that could impact force hide: " + win);
                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
-                        final int displayId = win.mDisplayContent.getDisplayId();
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -391,7 +395,6 @@
             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                 if (atoken == null || atoken.allDrawn) {
                     if (winAnimator.performShowLocked()) {
-                        final int displayId = win.mDisplayContent.getDisplayId();
                         mPendingLayoutChanges.put(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -427,10 +430,15 @@
         }
     }
 
-    private void updateWallpaperLocked(final WinAnimatorList winAnimatorList) {
+    private void updateWallpaperLocked(int displayId) {
+        final DisplayContentsAnimator displayAnimator =
+                getDisplayContentsAnimatorLocked(displayId);
+        final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
         WindowStateAnimator windowAnimationBackground = null;
         int windowAnimationBackgroundColor = 0;
         WindowState detachedWallpaper = null;
+        final DimSurface windowAnimationBackgroundSurface =
+                displayAnimator.mWindowAnimationBackgroundSurface;
 
         for (int i = winAnimatorList.size() - 1; i >= 0; i--) {
             WindowStateAnimator winAnimator = winAnimatorList.get(i);
@@ -510,11 +518,11 @@
                 }
             }
 
-            mWindowAnimationBackgroundSurface.show(mDw, mDh,
+            windowAnimationBackgroundSurface.show(mDw, mDh,
                     animLayer - WindowManagerService.LAYER_OFFSET_DIM,
                     windowAnimationBackgroundColor);
         } else {
-            mWindowAnimationBackgroundSurface.hide();
+            windowAnimationBackgroundSurface.hide();
         }
     }
 
@@ -557,9 +565,9 @@
         }
     }
 
-    private void performAnimationsLocked(final WinAnimatorList winAnimatorList) {
-        updateWindowsLocked(winAnimatorList);
-        updateWallpaperLocked(winAnimatorList);
+    private void performAnimationsLocked(final int displayId) {
+        updateWindowsLocked(displayId);
+        updateWallpaperLocked(displayId);
     }
 
     // TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
@@ -582,15 +590,30 @@
                 TAG, ">>> OPEN TRANSACTION animateLocked");
         Surface.openTransaction();
         try {
-            updateWindowsAppsAndRotationAnimationsLocked();
+            updateAppWindowsLocked();
 
-            for (int i = mWinAnimatorLists.size() - 1; i >= 0; i--) {
-                final WinAnimatorList winAnimatorList = mWinAnimatorLists.get(i);
+            final int numDisplays = mDisplayContentsAnimators.size();
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+
+                final ScreenRotationAnimation screenRotationAnimation =
+                        displayAnimator.mScreenRotationAnimation;
+                if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+                    if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
+                        mAnimating = true;
+                    } else {
+                        mBulkUpdateParams |= SET_UPDATE_ROTATION;
+                        screenRotationAnimation.kill();
+                        displayAnimator.mScreenRotationAnimation = null;
+                    }
+                }
 
                 // Update animations of all applications, including those
                 // associated with exiting/removed apps
-                performAnimationsLocked(winAnimatorList);
+                performAnimationsLocked(displayId);
 
+                final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
                 final int N = winAnimatorList.size();
                 for (int j = 0; j < N; j++) {
                     winAnimatorList.get(j).prepareSurfaceLocked(true);
@@ -599,16 +622,26 @@
 
             testTokenMayBeDrawnLocked();
 
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.updateSurfacesInTransaction();
-            }
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
-            if (mDimParams != null) {
-                mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime);
-            }
-            if (mDimAnimator != null && mDimAnimator.mDimShown) {
-                mAnimating |= mDimAnimator.updateSurface(isDimming(), mCurrentTime,
-                        !mService.okToDisplay());
+                final ScreenRotationAnimation screenRotationAnimation =
+                        displayAnimator.mScreenRotationAnimation;
+                if (screenRotationAnimation != null) {
+                    screenRotationAnimation.updateSurfacesInTransaction();
+                }
+
+                final DimAnimator.Parameters dimParams = displayAnimator.mDimParams;
+                final DimAnimator dimAnimator = displayAnimator.mDimAnimator;
+                if (dimParams != null) {
+                    dimAnimator.updateParameters(
+                            mContext.getResources(), dimParams, mCurrentTime);
+                }
+                if (dimAnimator != null && dimAnimator.mDimShown) {
+                    mAnimating |= dimAnimator.updateSurface(isDimmingLocked(displayId),
+                            mCurrentTime, !mService.okToDisplay());
+                }
             }
 
             if (mService.mWatermark != null) {
@@ -661,15 +694,17 @@
         mInnerDh = appHeight;
     }
 
-    boolean isDimming() {
-        return mDimParams != null;
+    boolean isDimmingLocked(int displayId) {
+        return getDisplayContentsAnimatorLocked(displayId).mDimParams != null;
     }
 
-    boolean isDimming(final WindowStateAnimator winAnimator) {
-        return mDimParams != null && mDimParams.mDimWinAnimator == winAnimator;
+    boolean isDimmingLocked(final WindowStateAnimator winAnimator) {
+        DimAnimator.Parameters dimParams =
+                getDisplayContentsAnimatorLocked(winAnimator.mWin.getDisplayId()).mDimParams;
+        return dimParams != null && dimParams.mDimWinAnimator == winAnimator;
     }
 
-    public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+    public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
         if (dumpAll) {
             if (mWindowDetachedWallpaper != null) {
                 pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
@@ -677,16 +712,36 @@
             }
             pw.print(prefix); pw.print("mAnimTransactionSequence=");
                     pw.println(mAnimTransactionSequence);
-            if (mWindowAnimationBackgroundSurface != null) {
-                pw.print(prefix); pw.print("mWindowAnimationBackgroundSurface:");
-                        mWindowAnimationBackgroundSurface.printTo(prefix + "  ", pw);
+            for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
+                pw.print(prefix); pw.print("DisplayContentsAnimator #");
+                    pw.println(mDisplayContentsAnimators.keyAt(i));
+                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+                final String subPrefix = "  " + prefix;
+                final String subSubPrefix = "  " + subPrefix;
+                if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
+                    pw.println(subPrefix + "mWindowAnimationBackgroundSurface:");
+                    displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
+                }
+                if (displayAnimator.mDimAnimator != null) {
+                    pw.println(subPrefix + "mDimAnimator:");
+                    displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
+                } else {
+                    pw.println(subPrefix + "no DimAnimator ");
+                }
+                if (displayAnimator.mDimParams != null) {
+                    pw.println(subPrefix + "mDimParams:");
+                    displayAnimator.mDimParams.printTo(subSubPrefix, pw);
+                } else {
+                    pw.println(subPrefix + "no DimParams ");
+                }
+                if (displayAnimator.mScreenRotationAnimation != null) {
+                    pw.println(subPrefix + "mScreenRotationAnimation:");
+                    displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
+                } else {
+                    pw.print(subPrefix + "no ScreenRotationAnimation ");
+                }
             }
-            if (mDimAnimator != null) {
-                pw.print(prefix); pw.print("mDimAnimator:");
-                mDimAnimator.printTo(prefix + "  ", pw);
-            } else {
-                pw.print(prefix); pw.print("no DimAnimator ");
-            }
+            pw.println();
         }
     }
 
@@ -716,4 +771,29 @@
             }
         }
     }
+
+    private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
+        DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
+        if (displayAnimator == null) {
+            displayAnimator = new DisplayContentsAnimator();
+            mDisplayContentsAnimators.put(displayId, displayAnimator);
+        }
+        return displayAnimator;
+    }
+
+    void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
+        getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+    }
+
+    ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
+        return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
+    }
+
+    private static class DisplayContentsAnimator {
+        WinAnimatorList mWinAnimators = new WinAnimatorList();
+        DimAnimator mDimAnimator = null;
+        DimAnimator.Parameters mDimParams = null;
+        DimSurface mWindowAnimationBackgroundSurface = null;
+        ScreenRotationAnimation mScreenRotationAnimation = null;
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 556613e..55a7c46 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -623,11 +623,11 @@
         long mChanges;
 
         boolean mAnimationScheduled;
-        ArrayList<WinAnimatorList> mWinAnimatorLists = new ArrayList<WinAnimatorList>();
+        SparseArray<WinAnimatorList> mWinAnimatorLists = new SparseArray<WinAnimatorList>();
         WindowState mWallpaperTarget;
         WindowState mLowerWallpaperTarget;
         WindowState mUpperWallpaperTarget;
-        DimAnimator.Parameters mDimParams;
+        SparseArray<DimAnimator.Parameters> mDimParams = new SparseArray<DimAnimator.Parameters>();
         ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
         ArrayList<AppWindowAnimParams> mAppWindowAnimParams = new ArrayList<AppWindowAnimParams>();
     }
@@ -4121,6 +4121,7 @@
         }
     }
 
+    @Override
     public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
             int startHeight) {
         synchronized(mWindowMap) {
@@ -4138,6 +4139,7 @@
         }
     }
 
+    @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
             int startY, IRemoteCallback startedCallback, boolean scaleUp) {
         synchronized(mWindowMap) {
@@ -4157,6 +4159,7 @@
         }
     }
 
+    @Override
     public void executeAppTransition() {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "executeAppTransition()")) {
@@ -5943,8 +5946,9 @@
             return false;
         }
 
-        if (mAnimator.mScreenRotationAnimation != null &&
-                mAnimator.mScreenRotationAnimation.isAnimating()) {
+        ScreenRotationAnimation screenRotationAnimation =
+                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
+        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
             // Rotation updates cannot be performed while the previous rotation change
             // animation is still in progress.  Skip this update.  We will try updating
             // again after the animation is finished and the display is unfrozen.
@@ -5996,6 +6000,9 @@
         mWaitingForConfig = true;
         getDefaultDisplayContentLocked().layoutNeeded = true;
         startFreezingDisplayLocked(inTransaction, 0, 0);
+        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
+        screenRotationAnimation =
+                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
 
         // We need to update our screen size information to match the new
         // rotation.  Note that this is redundant with the later call to
@@ -6016,9 +6023,9 @@
         try {
             // NOTE: We disable the rotation in the emulator because
             //       it doesn't support hardware OpenGL emulation yet.
-            if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
-                    && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
-                if (mAnimator.mScreenRotationAnimation.setRotationInTransaction(
+            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
+                    && screenRotationAnimation.hasScreenshot()) {
+                if (screenRotationAnimation.setRotationInTransaction(
                         rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         displayInfo.logicalWidth, displayInfo.logicalHeight)) {
@@ -7158,8 +7165,6 @@
             mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_TOUCHSCREEN);
 
-            mAnimator.initializeLocked(display.getLayerStack());
-
             final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
             mAnimator.setDisplayDimensions(
                     displayInfo.logicalWidth, displayInfo.logicalHeight,
@@ -7181,6 +7186,7 @@
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             final DisplayInfo displayInfo;
+            mAnimator.addDisplayLocked(displayId);
             synchronized(displayContent.mDisplaySizeLock) {
                 // Bootstrap the default logical display from the display manager.
                 displayInfo = displayContent.getDisplayInfo();
@@ -8136,7 +8142,7 @@
             if (winAnimator.mAnimLayer != oldLayer) {
                 layerChanged = true;
             }
-            if (layerChanged && mAnimator.isDimming(winAnimator)) {
+            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
                 // Force an animation pass just to update the mDimAnimator layer.
                 updateLayoutToAnimationLocked();
             }
@@ -8842,7 +8848,7 @@
                 //Slog.i(TAG, "DIM BEHIND: " + w);
                 mInnerFields.mDimming = true;
                 final WindowStateAnimator winAnimator = w.mWinAnimator;
-                if (!mAnimator.isDimming(winAnimator)) {
+                if (!mAnimator.isDimmingLocked(winAnimator)) {
                     final int width, height;
                     if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
                         final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
@@ -8852,7 +8858,8 @@
                         width = innerDw;
                         height = innerDh;
                     }
-                    startDimming(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
+                    startDimmingLocked(
+                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
                 }
             }
         }
@@ -9080,7 +9087,7 @@
                             }
                         }
 
-                        winAnimator.setSurfaceBoundaries(recoveringMemory);
+                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
 
                         final AppWindowToken atoken = w.mAppToken;
                         if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
@@ -9138,6 +9145,10 @@
 
                     updateResizingWindows(w);
                 }
+
+                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
+                    stopDimmingLocked(displayId);
+                }
             }
 
             if (updateAllDrawn) {
@@ -9147,10 +9158,6 @@
             if (focusDisplayed) {
                 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
             }
-
-            if (!mInnerFields.mDimming && mAnimator.isDimming()) {
-                stopDimming();
-            }
         } catch (RuntimeException e) {
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
@@ -9515,7 +9522,7 @@
         final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
         synchronized (layoutToAnim) {
             // Copy local params to transfer params.
-            ArrayList<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
+            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
             allWinAnimatorLists.clear();
             DisplayContentsIterator iterator = new DisplayContentsIterator();
             while (iterator.hasNext()) {
@@ -9529,7 +9536,7 @@
                         winAnimatorList.add(winAnimator);
                     }
                 }
-                allWinAnimatorLists.add(winAnimatorList);
+                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
             }
 
             layoutToAnim.mWallpaperTarget = mWallpaperTarget;
@@ -9555,20 +9562,21 @@
         }
     }
 
-    void setAnimDimParams(DimAnimator.Parameters params) {
+    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
         synchronized (mLayoutToAnim) {
-            mLayoutToAnim.mDimParams = params;
+            mLayoutToAnim.mDimParams.put(displayId, params);
             scheduleAnimationLocked();
         }
     }
 
-    void startDimming(final WindowStateAnimator winAnimator, final float target,
+    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
                       final int width, final int height) {
-        setAnimDimParams(new DimAnimator.Parameters(winAnimator, width, height, target));
+        setAnimDimParams(winAnimator.mWin.getDisplayId(),
+                new DimAnimator.Parameters(winAnimator, width, height, target));
     }
 
-    void stopDimming() {
-        setAnimDimParams(null);
+    void stopDimmingLocked(int displayId) {
+        setAnimDimParams(displayId, null);
     }
 
     private boolean needsLayout() {
@@ -9900,19 +9908,22 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
-            if (mAnimator.mScreenRotationAnimation != null) {
-                mAnimator.mScreenRotationAnimation.kill();
-                mAnimator.mScreenRotationAnimation = null;
+            final DisplayContent displayContent = getDefaultDisplayContentLocked();
+            final int displayId = displayContent.getDisplayId();
+            ScreenRotationAnimation screenRotationAnimation =
+                    mAnimator.getScreenRotationAnimationLocked(displayId);
+            if (screenRotationAnimation != null) {
+                screenRotationAnimation.kill();
             }
 
             // TODO(multidisplay): rotation on main screen only.
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
             final Display display = displayContent.getDisplay();
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+            screenRotationAnimation = new ScreenRotationAnimation(mContext,
                     display, mFxSession, inTransaction, displayInfo.logicalWidth,
                     displayInfo.logicalHeight, display.getRotation(),
                     exitAnim, enterAnim);
+            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
         }
     }
 
@@ -9940,24 +9951,30 @@
 
         boolean updateRotation = false;
 
-        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
-                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        final int displayId = displayContent.getDisplayId();
+        ScreenRotationAnimation screenRotationAnimation =
+                mAnimator.getScreenRotationAnimationLocked(displayId);
+        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
+                && screenRotationAnimation.hasScreenshot()) {
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             // TODO(multidisplay): rotation on main screen only.
-            DisplayInfo displayInfo = getDefaultDisplayContentLocked().getDisplayInfo();
-            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
+            DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, displayInfo.logicalWidth,
                         displayInfo.logicalHeight)) {
                 updateLayoutToAnimationLocked();
             } else {
-                mAnimator.mScreenRotationAnimation.kill();
-                mAnimator.mScreenRotationAnimation = null;
+                screenRotationAnimation.kill();
+                screenRotationAnimation = null;
+                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
                 updateRotation = true;
             }
         } else {
-            if (mAnimator.mScreenRotationAnimation != null) {
-                mAnimator.mScreenRotationAnimation.kill();
-                mAnimator.mScreenRotationAnimation = null;
+            if (screenRotationAnimation != null) {
+                screenRotationAnimation.kill();
+                screenRotationAnimation = null;
+                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
             }
             updateRotation = true;
         }
@@ -10394,11 +10411,11 @@
                         pw.print(": "); pw.println(pair.second);
             }
         }
-        pw.println();
+        pw.println("  DisplayContents");
         if (mDisplayReady) {
             DisplayContentsIterator dCIterator = new DisplayContentsIterator();
             while (dCIterator.hasNext()) {
-                dCIterator.next().dump(pw);
+                dCIterator.next().dump("    ", pw);
             }
         } else {
             pw.println("  NO DISPLAY");
@@ -10463,10 +10480,6 @@
             pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            if (mAnimator.mScreenRotationAnimation != null) {
-                pw.println("  mScreenRotationAnimation:");
-                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
-            }
             pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
                     pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
                     pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
@@ -10515,7 +10528,7 @@
             pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
                     pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
             pw.println("  Window Animator:");
-            mAnimator.dump(pw, "    ", dumpAll);
+            mAnimator.dumpLocked(pw, "    ", dumpAll);
         }
     }
 
@@ -10850,6 +10863,7 @@
 
     private void handleDisplayAddedLocked(int displayId) {
         createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
+        displayReady(displayId);
     }
 
     @Override
@@ -10865,6 +10879,7 @@
             final WindowState win = windows.get(i);
             removeWindowLocked(win.mSession, win);
         }
+        mAnimator.removeDisplayLocked(displayId);
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 8912c73..000a191 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -31,6 +31,13 @@
 import java.util.ArrayList;
 
 class WinAnimatorList extends ArrayList<WindowStateAnimator> {
+    public WinAnimatorList() {
+        super();
+    }
+
+    public WinAnimatorList(WinAnimatorList other) {
+        super(other);
+    }
 }
 
 /**
@@ -840,8 +847,11 @@
             }
         }
 
-        final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null
-                && mService.mAnimator.mScreenRotationAnimation.isAnimating();
+        final int displayId = mWin.getDisplayId();
+        final ScreenRotationAnimation screenRotationAnimation =
+                mAnimator.getScreenRotationAnimationLocked(displayId);
+        final boolean screenAnimation =
+                screenRotationAnimation != null && screenRotationAnimation.isAnimating();
         if (selfTransformation || attachedTransformation != null
                 || appTransformation != null || screenAnimation) {
             // cache often used attributes locally
@@ -883,8 +893,7 @@
                 tmpMatrix.postConcat(mAnimator.mUniverseBackground.mUniverseTransform.getMatrix());
             }
             if (screenAnimation) {
-                tmpMatrix.postConcat(
-                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix());
+                tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
             MagnificationSpec spec = mWin.getWindowMagnificationSpecLocked();
             if (spec != null && !spec.isNop()) {
@@ -934,21 +943,21 @@
                     mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
                 }
                 if (screenAnimation) {
-                    mShownAlpha *=
-                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha();
+                    mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
                 }
             } else {
                 //Slog.i(TAG, "Not applying alpha transform");
             }
 
-            if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV) && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
-                TAG, "computeShownFrameLocked: Animating " + this +
-                " mAlpha=" + mAlpha +
-                " self=" + (selfTransformation ? mTransformation.getAlpha() : "null") +
-                " attached=" + (attachedTransformation == null ? "null" : attachedTransformation.getAlpha()) +
-                " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha()) +
-                " screen=" + (screenAnimation ? mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha()
-                        : "null"));
+            if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
+                    && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
+                    TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
+                    + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
+                    + " attached=" + (attachedTransformation == null ?
+                            "null" : attachedTransformation.getAlpha())
+                    + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
+                    + " screen=" + (screenAnimation ?
+                            screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
             return;
         } else if (mIsWallpaper &&
                     (mAnimator.mPendingActions & WindowAnimator.WALLPAPER_ACTION_PENDING) != 0) {
@@ -1083,7 +1092,7 @@
         }
     }
 
-    void setSurfaceBoundaries(final boolean recoveringMemory) {
+    void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
         int width, height;
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1138,7 +1147,7 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
                     final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
-                    mService.startDimming(this, w.mExiting ? 0 : w.mAttrs.dimAmount,
+                    mService.startDimmingLocked(this, w.mExiting ? 0 : w.mAttrs.dimAmount,
                             displayInfo.appWidth, displayInfo.appHeight);
                 }
             } catch (RuntimeException e) {
@@ -1172,7 +1181,7 @@
 
         computeShownFrameLocked();
 
-        setSurfaceBoundaries(recoveringMemory);
+        setSurfaceBoundariesLocked(recoveringMemory);
 
         if (mIsWallpaper && !mWin.mWallpaperVisible) {
             // Wallpaper is no longer visible and there is no wp target => hide it.