Merge "Add overflow menu popup for Action Bar in Layoutlib"
diff --git a/Android.mk b/Android.mk
index 84d5dc5..adc9ef1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -420,6 +420,8 @@
 	frameworks/base/core/java/android/view/MotionEvent.aidl \
 	frameworks/base/core/java/android/view/Surface.aidl \
 	frameworks/base/core/java/android/view/WindowManager.aidl \
+	frameworks/base/core/java/android/view/WindowAnimationFrameStats.aidl \
+	frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
 	frameworks/base/core/java/android/widget/RemoteViews.aidl \
 	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
 	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
diff --git a/api/current.txt b/api/current.txt
index 15351de..2274ea0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35,6 +35,7 @@
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+    field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -2456,6 +2457,7 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
@@ -4453,6 +4455,7 @@
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
+    method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
@@ -4751,9 +4754,14 @@
   }
 
   public final class UiAutomation {
+    method public void clearWindowAnimationFrameStats();
+    method public boolean clearWindowContentFrameStats(int);
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+    method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
+    method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
     method public final boolean performGlobalAction(int);
@@ -4948,6 +4956,7 @@
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
+    method public void setProfileEnabled(android.content.ComponentName);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
@@ -7776,6 +7785,7 @@
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11026,8 +11036,6 @@
     method public void setAnimationFraction(float);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setDuration(long);
-    method public void setIntrinsicHeight(int);
-    method public void setIntrinsicWidth(int);
     method public void setPadding(android.graphics.Rect);
     method public void setPadding(int, int, int, int);
     method public void setRepeatCount(int);
@@ -11391,10 +11399,33 @@
     method public int getMinDelay();
     method public java.lang.String getName();
     method public float getPower();
+    method public java.lang.String getRequiredPermission();
     method public float getResolution();
+    method public java.lang.String getStringType();
     method public int getType();
     method public java.lang.String getVendor();
     method public int getVersion();
+    field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+    field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+    field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+    field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
+    field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+    field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+    field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+    field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+    field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+    field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+    field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -11403,6 +11434,7 @@
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
@@ -12155,6 +12187,7 @@
   public final class HdmiCecClient {
     method public boolean isTvOn();
     method public void sendActiveSource();
+    method public void sendGiveDevicePowerStatus(int);
     method public void sendImageViewOn();
     method public void sendInactiveSource();
     method public void sendTextViewOn();
@@ -15775,10 +15808,13 @@
   public final class NsdServiceInfo implements android.os.Parcelable {
     ctor public NsdServiceInfo();
     method public int describeContents();
+    method public java.util.Map<java.lang.String, byte[]> getAttributes();
     method public java.net.InetAddress getHost();
     method public int getPort();
     method public java.lang.String getServiceName();
     method public java.lang.String getServiceType();
+    method public void removeAttribute(java.lang.String);
+    method public void setAttribute(java.lang.String, java.lang.String);
     method public void setHost(java.net.InetAddress);
     method public void setPort(int);
     method public void setServiceName(java.lang.String);
@@ -19732,7 +19768,8 @@
 
   public final class PowerManager {
     method public void goToSleep(long);
-    method public boolean isScreenOn();
+    method public boolean isInteractive();
+    method public deprecated boolean isScreenOn();
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
     method public void userActivity(long, boolean);
@@ -19944,6 +19981,7 @@
 
   public class UserManager {
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
+    method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -23317,6 +23355,67 @@
     field public static final java.lang.String TYPE = "type";
   }
 
+  public final class TvContract {
+    method public static final android.net.Uri buildChannelUri(long);
+    method public static final android.net.Uri buildProgramUri(long);
+    field public static final java.lang.String AUTHORITY = "com.android.tv";
+  }
+
+  public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String PACKAGE_NAME = "package_name";
+  }
+
+  public static final class TvContract.Channels implements android.provider.TvContract.BaseTvColumns {
+    field public static final java.lang.String BROWSABLE = "browsable";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.channels";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.channels";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATA = "data";
+    field public static final java.lang.String DESCRIPTION = "description";
+    field public static final java.lang.String DISPLAY_NAME = "display_name";
+    field public static final java.lang.String DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String SERVICE_NAME = "service_name";
+    field public static final java.lang.String TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String TYPE = "type";
+    field public static final int TYPE_1SEG = 263168; // 0x40400
+    field public static final int TYPE_ATSC = 196608; // 0x30000
+    field public static final int TYPE_ATSC_2_0 = 196609; // 0x30001
+    field public static final int TYPE_ATSC_M_H = 196864; // 0x30100
+    field public static final int TYPE_CMMB = 327936; // 0x50100
+    field public static final int TYPE_DTMB = 327680; // 0x50000
+    field public static final int TYPE_DVB_C = 131584; // 0x20200
+    field public static final int TYPE_DVB_C2 = 131585; // 0x20201
+    field public static final int TYPE_DVB_H = 131840; // 0x20300
+    field public static final int TYPE_DVB_S = 131328; // 0x20100
+    field public static final int TYPE_DVB_S2 = 131329; // 0x20101
+    field public static final int TYPE_DVB_SH = 132096; // 0x20400
+    field public static final int TYPE_DVB_T = 131072; // 0x20000
+    field public static final int TYPE_DVB_T2 = 131073; // 0x20001
+    field public static final int TYPE_ISDB_C = 262912; // 0x40300
+    field public static final int TYPE_ISDB_S = 262656; // 0x40200
+    field public static final int TYPE_ISDB_T = 262144; // 0x40000
+    field public static final int TYPE_ISDB_TB = 262400; // 0x40100
+    field public static final int TYPE_OTHER = 0; // 0x0
+    field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
+    field public static final int TYPE_S_DMB = 393472; // 0x60100
+    field public static final int TYPE_T_DMB = 393216; // 0x60000
+    field public static final java.lang.String VERSION_NUMBER = "version_number";
+  }
+
+  public static final class TvContract.Programs implements android.provider.TvContract.BaseTvColumns {
+    field public static final java.lang.String CHANNEL_ID = "channel_id";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.programs";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.programs";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATA = "data";
+    field public static final java.lang.String DESCRIPTION = "description";
+    field public static final java.lang.String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String TITLE = "title";
+    field public static final java.lang.String VERSION_NUMBER = "version_number";
+  }
+
   public class UserDictionary {
     ctor public UserDictionary();
     field public static final java.lang.String AUTHORITY = "user_dictionary";
@@ -24803,7 +24902,7 @@
     method public abstract void onUtteranceCompleted(java.lang.String);
   }
 
-  public final class TextToSpeechClient {
+  public class TextToSpeechClient {
     ctor public TextToSpeechClient(android.content.Context, java.lang.String, boolean, android.speech.tts.TextToSpeechClient.RequestCallbacks, android.speech.tts.TextToSpeechClient.ConnectionCallbacks);
     ctor public TextToSpeechClient(android.content.Context, android.speech.tts.TextToSpeechClient.RequestCallbacks, android.speech.tts.TextToSpeechClient.ConnectionCallbacks);
     method public void connect();
@@ -25997,6 +26096,7 @@
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -28409,6 +28509,7 @@
     method public float getRefreshRate();
     method public int getRotation();
     method public void getSize(android.graphics.Point);
+    method public int getState();
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -28416,6 +28517,10 @@
     field public static final int FLAG_PRIVATE = 4; // 0x4
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+    field public static final int STATE_DOZING = 3; // 0x3
+    field public static final int STATE_OFF = 1; // 0x1
+    field public static final int STATE_ON = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public class DragEvent implements android.os.Parcelable {
@@ -28444,6 +28549,18 @@
     method public static android.view.FocusFinder getInstance();
   }
 
+  public abstract class FrameStats {
+    ctor public FrameStats();
+    method public final long getEndTimeNano();
+    method public final int getFrameCount();
+    method public final long getFramePresentedTimeNano(int);
+    method public final long getRefreshPeriodNano();
+    method public final long getStartTimeNano();
+    field public static final long UNDEFINED_TIME_NANO = -1L; // 0xffffffffffffffffL
+    field protected long[] mFramesPresentedTimeNano;
+    field protected long mRefreshPeriodNano;
+  }
+
   public class GestureDetector {
     ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler);
     ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener);
@@ -28749,7 +28866,7 @@
     field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
     field public static final int FLAG_TRACKING = 512; // 0x200
     field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
-    field public static final int FLAG_WOKE_HERE = 1; // 0x1
+    field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
     field public static final int KEYCODE_0 = 7; // 0x7
     field public static final int KEYCODE_1 = 8; // 0x8
     field public static final int KEYCODE_2 = 9; // 0x9
@@ -30768,6 +30885,20 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
   }
 
+  public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class WindowContentFrameStats extends android.view.FrameStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getFramePostedTimeNano(int);
+    method public long getFrameReadyTimeNano(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class WindowId implements android.os.Parcelable {
     method public int describeContents();
     method public boolean isFocused();
@@ -30869,7 +31000,7 @@
     field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
     field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
     field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
-    field public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+    field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
     field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
     field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
     field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 3e8d6a0..859d83b 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -97,7 +97,7 @@
 
     virtual void onExit(int code)
     {
-        if (mClassName == NULL) {
+        if (mClassName.isEmpty()) {
             // if zygote
             IPCThreadState::self()->stopProcess();
         }
@@ -138,8 +138,10 @@
 
 #if defined(__LP64__)
 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
+static const char ZYGOTE_NICE_NAME[] = "zygote64";
 #else
 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
+static const char ZYGOTE_NICE_NAME[] = "zygote";
 #endif
 
 int main(int argc, char* const argv[])
@@ -185,16 +187,19 @@
         const char* arg = argv[i++];
         if (strcmp(arg, "--zygote") == 0) {
             zygote = true;
-            niceName = "zygote";
+            niceName = ZYGOTE_NICE_NAME;
         } else if (strcmp(arg, "--start-system-server") == 0) {
             startSystemServer = true;
         } else if (strcmp(arg, "--application") == 0) {
             application = true;
         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
             niceName = arg + 12;
-        } else {
+        } else if (strncmp(arg, "--", 2) != 0) {
             className.setTo(arg);
             break;
+        } else {
+            --i;
+            break;
         }
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b01d92c..2620c44 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -526,6 +526,31 @@
     }
 
     /**
+     * Find the view that has the specified focus type. The search is performed
+     * across all windows.
+     * <p>
+     * <strong>Note:</strong> In order to access the windows your service has
+     * to declare the capability to retrieve window content by setting the
+     * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
+     * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
+     * Also the service has to opt-in to retrieve the interactive windows by
+     * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
+     * flag.Otherwise, the search will be performed only in the active window.
+     * </p>
+     *
+     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     *
+     * @see AccessibilityNodeInfo#FOCUS_INPUT
+     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+                AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+    }
+
+    /**
      * Gets the an {@link AccessibilityServiceInfo} describing this
      * {@link AccessibilityService}. This method is useful if one wants
      * to change some of the dynamically configurable properties at
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..f9af979
--- /dev/null
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+    private static final String TAG = "AlsaCardsParser";
+
+    private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
+
+    public class AlsaCardRecord {
+        public int mCardNum = -1;
+        public String mField1 = "";
+        public String mCardName = "";
+        public String mCardDescription = "";
+
+        public AlsaCardRecord() {}
+
+        public boolean parse(String line, int lineIndex) {
+            int tokenIndex = 0;
+            int delimIndex = 0;
+            if (lineIndex == 0) {
+                // line # (skip)
+                tokenIndex = tokenizer_.nextToken(line, tokenIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+
+                // mField1
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mField1 = line.substring(tokenIndex, delimIndex);
+
+                // mCardName
+                tokenIndex = tokenizer_.nextToken(line, delimIndex);
+                // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+                mCardName = line.substring(tokenIndex);
+                // done
+              } else if (lineIndex == 1) {
+                  tokenIndex = tokenizer_.nextToken(line, 0);
+                  if (tokenIndex != -1) {
+                      mCardDescription = line.substring(tokenIndex);
+                  }
+            }
+
+            return true;
+        }
+
+        public String textFormat() {
+          return mCardName + " : " + mCardDescription;
+        }
+    }
+
+    private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
+
+    public void scan() {
+          cardRecords_.clear();
+          final String cardsFilePath = "/proc/asound/cards";
+          File cardsFile = new File(cardsFilePath);
+          try {
+              FileReader reader = new FileReader(cardsFile);
+              BufferedReader bufferedReader = new BufferedReader(reader);
+              String line = "";
+              while ((line = bufferedReader.readLine()) != null) {
+                  AlsaCardRecord cardRecord = new AlsaCardRecord();
+                  cardRecord.parse(line, 0);
+                  cardRecord.parse(line = bufferedReader.readLine(), 1);
+                  cardRecords_.add(cardRecord);
+              }
+              reader.close();
+          } catch (FileNotFoundException e) {
+              e.printStackTrace();
+          } catch (IOException e) {
+              e.printStackTrace();
+          }
+      }
+
+      public AlsaCardRecord getCardRecordAt(int index) {
+          return cardRecords_.get(index);
+      }
+
+      public int getNumCardRecords() {
+          return cardRecords_.size();
+      }
+
+    public void Log() {
+      int numCardRecs = getNumCardRecords();
+      for (int index = 0; index < numCardRecs; ++index) {
+          Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
+      }
+    }
+
+    public AlsaCardsParser() {}
+}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..094c8a2
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+    private static final String TAG = "AlsaDevicesParser";
+
+    private static final int kIndex_CardDeviceField = 5;
+    private static final int kStartIndex_CardNum = 6;
+    private static final int kEndIndex_CardNum = 8; // one past
+    private static final int kStartIndex_DeviceNum = 9;
+    private static final int kEndIndex_DeviceNum = 11; // one past
+    private static final int kStartIndex_Type = 14;
+
+    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+    private boolean mHasCaptureDevices = false;
+    private boolean mHasPlaybackDevices = false;
+    private boolean mHasMIDIDevices = false;
+
+    public class AlsaDeviceRecord {
+        public static final int kDeviceType_Unknown = -1;
+        public static final int kDeviceType_Audio = 0;
+        public static final int kDeviceType_Control = 1;
+        public static final int kDeviceType_MIDI = 2;
+
+        public static final int kDeviceDir_Unknown = -1;
+        public static final int kDeviceDir_Capture = 0;
+        public static final int kDeviceDir_Playback = 1;
+
+        int mCardNum = -1;
+        int mDeviceNum = -1;
+        int mDeviceType = kDeviceType_Unknown;
+        int mDeviceDir = kDeviceDir_Unknown;
+
+        public AlsaDeviceRecord() {
+        }
+
+        public boolean parse(String line) {
+            // "0123456789012345678901234567890"
+            // "  2: [ 0-31]: digital audio playback"
+            // "  3: [ 0-30]: digital audio capture"
+            // " 35: [ 1]   : control"
+            // " 36: [ 2- 0]: raw midi"
+
+            final int kToken_LineNum = 0;
+            final int kToken_CardNum = 1;
+            final int kToken_DeviceNum = 2;
+            final int kToken_Type0 = 3; // "digital", "control", "raw"
+            final int kToken_Type1 = 4; // "audio", "midi"
+            final int kToken_Type2 = 5; // "capture", "playback"
+
+            int tokenOffset = 0;
+            int delimOffset = 0;
+            int tokenIndex = kToken_LineNum;
+            while (true) {
+                tokenOffset = mTokenizer.nextToken(line, delimOffset);
+                if (tokenOffset == LineTokenizer.kTokenNotFound) {
+                    break; // bail
+                }
+                delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+                if (delimOffset == LineTokenizer.kTokenNotFound) {
+                    delimOffset = line.length();
+                }
+                String token = line.substring(tokenOffset, delimOffset);
+
+                switch (tokenIndex) {
+                case kToken_LineNum:
+                    // ignore
+                    break;
+
+                case kToken_CardNum:
+                    mCardNum = Integer.parseInt(token);
+                    if (line.charAt(delimOffset) != '-') {
+                        tokenIndex++; // no device # in the token stream
+                    }
+                    break;
+
+                case kToken_DeviceNum:
+                    mDeviceNum = Integer.parseInt(token);
+                    break;
+
+                case kToken_Type0:
+                    if (token.equals("digital")) {
+                        // NOP
+                    } else if (token.equals("control")) {
+                        mDeviceType = kDeviceType_Control;
+                    } else if (token.equals("raw")) {
+                        // NOP
+                    }
+                    break;
+
+                case kToken_Type1:
+                    if (token.equals("audio")) {
+                        mDeviceType = kDeviceType_Audio;
+                    } else if (token.equals("midi")) {
+                        mDeviceType = kDeviceType_MIDI;
+                        mHasMIDIDevices = true;
+                    }
+                    break;
+
+                case kToken_Type2:
+                    if (token.equals("capture")) {
+                        mDeviceDir = kDeviceDir_Capture;
+                        mHasCaptureDevices = true;
+                    } else if (token.equals("playback")) {
+                        mDeviceDir = kDeviceDir_Playback;
+                        mHasPlaybackDevices = true;
+                    }
+                    break;
+                } // switch (tokenIndex)
+
+                tokenIndex++;
+            } // while (true)
+
+            return true;
+        } // parse()
+
+        public String textFormat() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+            switch (mDeviceType) {
+            case kDeviceType_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceType_Audio:
+                sb.append(" Audio");
+                break;
+            case kDeviceType_Control:
+                sb.append(" Control");
+                break;
+            case kDeviceType_MIDI:
+                sb.append(" MIDI");
+                break;
+            }
+
+            switch (mDeviceDir) {
+            case kDeviceDir_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceDir_Capture:
+                sb.append(" Capture");
+                break;
+            case kDeviceDir_Playback:
+                sb.append(" Playback");
+                break;
+            }
+
+            return sb.toString();
+        }
+    }
+
+    private Vector<AlsaDeviceRecord>
+            deviceRecords_ = new Vector<AlsaDeviceRecord>();
+
+    private boolean isLineDeviceRecord(String line) {
+        return line.charAt(kIndex_CardDeviceField) == '[';
+    }
+
+    public AlsaDevicesParser() {
+    }
+
+    public int getNumDeviceRecords() {
+        return deviceRecords_.size();
+    }
+
+    public AlsaDeviceRecord getDeviceRecordAt(int index) {
+        return deviceRecords_.get(index);
+    }
+
+    public void Log() {
+        int numDevRecs = getNumDeviceRecords();
+        for (int index = 0; index < numDevRecs; ++index) {
+            Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
+        }
+    }
+
+    public boolean hasPlaybackDevices() {
+        return mHasPlaybackDevices;
+    }
+
+    public boolean hasPlaybackDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasCaptureDevices() {
+        return mHasCaptureDevices;
+    }
+
+    public boolean hasCaptureDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasMIDIDevices() {
+        return mHasMIDIDevices;
+    }
+
+    public boolean hasMIDIDevices(int card) {
+        for (int index = 0; index < deviceRecords_.size(); index++) {
+            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void scan() {
+        deviceRecords_.clear();
+
+        final String devicesFilePath = "/proc/asound/devices";
+        File devicesFile = new File(devicesFilePath);
+        try {
+            FileReader reader = new FileReader(devicesFile);
+            BufferedReader bufferedReader = new BufferedReader(reader);
+            String line = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                if (isLineDeviceRecord(line)) {
+                    AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+                    deviceRecord.parse(line);
+                    deviceRecords_.add(deviceRecord);
+                }
+            }
+            reader.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+} // class AlsaDevicesParser
+
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
new file mode 100644
index 0000000..c138fc5
--- /dev/null
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+    public static final int kTokenNotFound = -1;
+
+    private String mDelimiters = "";
+
+    public LineTokenizer(String delimiters) {
+        mDelimiters = delimiters;
+    }
+
+    int nextToken(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+                // past a delimiter
+                break;
+            }
+      }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+
+    int nextDelimiter(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+                // past a delimiter
+                break;
+            }
+        }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 34b0f3a..9818c33 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1239,6 +1239,8 @@
 
         public LayoutParams(int width, int height, int gravity) {
             super(width, height);
+
+            this.gravity = gravity;
         }
 
         public LayoutParams(int gravity) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6ca5244..ab62427 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -128,6 +128,24 @@
     }
 
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        // Try to find a main leanback_launcher activity.
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+        intentToResolve.setPackage(packageName);
+        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+        if (ris == null || ris.size() <= 0) {
+            return null;
+        }
+        Intent intent = new Intent(intentToResolve);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(ris.get(0).activityInfo.packageName,
+                ris.get(0).activityInfo.name);
+        return intent;
+    }
+
+    @Override
     public int[] getPackageGids(String packageName)
             throws NameNotFoundException {
         try {
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 09bf829..347de97 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -19,6 +19,8 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.graphics.Bitmap;
 import android.view.InputEvent;
+import android.view.WindowContentFrameStats;
+import android.view.WindowAnimationFrameStats;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -26,7 +28,7 @@
  * on behalf of an instrumentation that it runs. These operations require
  * special permissions which the shell user has but the instrumentation does
  * not. Running privileged operations by the shell user on behalf of an
- * instrumentation is needed for running UiTestCases. 
+ * instrumentation is needed for running UiTestCases.
  *
  * {@hide}
  */
@@ -37,4 +39,8 @@
     boolean setRotation(int rotation);
     Bitmap takeScreenshot(int width, int height);
     void shutdown();
+    boolean clearWindowContentFrameStats(int windowId);
+    WindowContentFrameStats getWindowContentFrameStats(int windowId);
+    void clearWindowAnimationFrameStats();
+    WindowAnimationFrameStats getWindowAnimationFrameStats();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 36d2635..fe629f6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1311,6 +1311,7 @@
         private Notification mPublicVersion = null;
         private boolean mQuantumTheme;
         private final LegacyNotificationUtil mLegacyNotificationUtil;
+        private ArrayList<String> mPeople;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -1338,6 +1339,7 @@
             mWhen = System.currentTimeMillis();
             mAudioStreamType = STREAM_DEFAULT;
             mPriority = PRIORITY_DEFAULT;
+            mPeople = new ArrayList<String>();
 
             // TODO: Decide on targetSdk from calling app whether to use quantum theme.
             mQuantumTheme = true;
@@ -1723,6 +1725,16 @@
         }
 
         /**
+         * Add a person that is relevant to this notification.
+         *
+         * @see Notification#EXTRA_PEOPLE
+         */
+        public Builder addPerson(String handle) {
+            mPeople.add(handle);
+            return this;
+        }
+
+        /**
          * Merge additional metadata into this notification.
          *
          * <p>Values within the Bundle will replace existing extras values in this Builder.
@@ -2149,6 +2161,9 @@
             if (mLargeIcon != null) {
                 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
             }
+            if (!mPeople.isEmpty()) {
+                extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()]));
+            }
         }
 
         /**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 354a19f..9405325 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -33,6 +33,8 @@
 import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.Surface;
+import android.view.WindowAnimationFrameStats;
+import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -295,6 +297,28 @@
     }
 
     /**
+     * Find the view that has the specified focus type. The search is performed
+     * across all windows.
+     * <p>
+     * <strong>Note:</strong> In order to access the windows you have to opt-in
+     * to retrieve the interactive windows by setting the
+     * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
+     * Otherwise, the search will be performed only in the active window.
+     * </p>
+     *
+     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     *
+     * @see AccessibilityNodeInfo#FOCUS_INPUT
+     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
+     */
+    public AccessibilityNodeInfo findFocus(int focus) {
+        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
+                AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
+    }
+
+    /**
      * Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
      * This method is useful if one wants to change some of the dynamically
      * configurable properties at runtime.
@@ -674,6 +698,148 @@
         }
     }
 
+    /**
+     * Clears the frame statistics for the content of a given window. These
+     * statistics contain information about the most recently rendered content
+     * frames.
+     *
+     * @param windowId The window id.
+     * @return Whether the window is present and its frame statistics
+     *         were cleared.
+     *
+     * @see android.view.WindowContentFrameStats
+     * @see #getWindowContentFrameStats(int)
+     * @see #getWindows()
+     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
+     */
+    public boolean clearWindowContentFrameStats(int windowId) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId);
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.clearWindowContentFrameStats(windowId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error clearing window content frame stats!", re);
+        }
+        return false;
+    }
+
+    /**
+     * Gets the frame statistics for a given window. These statistics contain
+     * information about the most recently rendered content frames.
+     * <p>
+     * A typical usage requires clearing the window frame statistics via {@link
+     * #clearWindowContentFrameStats(int)} followed by an interaction with the UI and
+     * finally getting the window frame statistics via calling this method.
+     * </p>
+     * <pre>
+     * // Assume we have at least one window.
+     * final int windowId = getWindows().get(0).getId();
+     *
+     * // Start with a clean slate.
+     * uiAutimation.clearWindowContentFrameStats(windowId);
+     *
+     * // Do stuff with the UI.
+     *
+     * // Get the frame statistics.
+     * WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId);
+     * </pre>
+     *
+     * @param windowId The window id.
+     * @return The window frame statistics, or null if the window is not present.
+     *
+     * @see android.view.WindowContentFrameStats
+     * @see #clearWindowContentFrameStats(int)
+     * @see #getWindows()
+     * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId()
+     */
+    public WindowContentFrameStats getWindowContentFrameStats(int windowId) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId);
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.getWindowContentFrameStats(windowId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting window content frame stats!", re);
+        }
+        return null;
+    }
+
+    /**
+     * Clears the window animation rendering statistics. These statistics contain
+     * information about the most recently rendered window animation frames, i.e.
+     * for window transition animations.
+     *
+     * @see android.view.WindowAnimationFrameStats
+     * @see #getWindowAnimationFrameStats()
+     * @see android.R.styleable#WindowAnimation
+     */
+    public void clearWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Clearing window animation frame stats");
+            }
+            // Calling out without a lock held.
+            mUiAutomationConnection.clearWindowAnimationFrameStats();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error clearing window animation frame stats!", re);
+        }
+    }
+
+    /**
+     * Gets the window animation frame statistics. These statistics contain
+     * information about the most recently rendered window animation frames, i.e.
+     * for window transition animations.
+     *
+     * <p>
+     * A typical usage requires clearing the window animation frame statistics via
+     * {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes
+     * a window transition which uses a window animation and finally getting the window
+     * animation frame statistics by calling this method.
+     * </p>
+     * <pre>
+     * // Start with a clean slate.
+     * uiAutimation.clearWindowAnimationFrameStats();
+     *
+     * // Do stuff to trigger a window transition.
+     *
+     * // Get the frame statistics.
+     * WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
+     * </pre>
+     *
+     * @return The window animation frame statistics.
+     *
+     * @see android.view.WindowAnimationFrameStats
+     * @see #clearWindowAnimationFrameStats()
+     * @see android.R.styleable#WindowAnimation
+     */
+    public WindowAnimationFrameStats getWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+        try {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Getting window animation frame stats");
+            }
+            // Calling out without a lock held.
+            return mUiAutomationConnection.getWindowAnimationFrameStats();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting window animation frame stats!", re);
+        }
+        return null;
+    }
+
     private static float getDegreesForRotation(int value) {
         switch (value) {
             case Surface.ROTATION_90: {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 91b0d7c..fa40286 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -22,12 +22,15 @@
 import android.graphics.Bitmap;
 import android.hardware.input.InputManager;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.view.IWindowManager;
 import android.view.InputEvent;
 import android.view.SurfaceControl;
+import android.view.WindowAnimationFrameStats;
+import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
 
@@ -47,6 +50,9 @@
     private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
             ServiceManager.getService(Service.WINDOW_SERVICE));
 
+    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface(
+            ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
+
     private final Object mLock = new Object();
 
     private final Binder mToken = new Binder();
@@ -144,6 +150,76 @@
     }
 
     @Override
+    public boolean clearWindowContentFrameStats(int windowId) throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            if (token == null) {
+                return false;
+            }
+            return mWindowManager.clearWindowContentFrameStats(token);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(int windowId) throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            if (token == null) {
+                return null;
+            }
+            return mWindowManager.getWindowContentFrameStats(token);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void clearWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            SurfaceControl.clearAnimationFrameStats();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public WindowAnimationFrameStats getWindowAnimationFrameStats() {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            WindowAnimationFrameStats stats = new WindowAnimationFrameStats();
+            SurfaceControl.getAnimationFrameStats(stats);
+            return stats;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void shutdown() {
         synchronized (mLock) {
             if (isConnectedLocked()) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d8be439..725f808 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1756,8 +1756,26 @@
     }
 
     /**
+     * Sets the enabled state of the profile. A profile should be enabled only once it is ready to
+     * be used. Only the profile owner can call this.
+     *
+     * @see #isPRofileOwnerApp
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public void setProfileEnabled(ComponentName admin) {
+        if (mService != null) {
+            try {
+                mService.setProfileEnabled(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
      * Used to determine if a particular package is registered as the Profile Owner for the
-     * current user. A profile owner is a special device admin that has additional priviledges
+     * current user. A profile owner is a special device admin that has additional privileges
      * within the managed profile.
      *
      * @param packageName The package name of the app to compare with the registered profile owner.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8119585..e4b2adc 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -107,6 +107,7 @@
     boolean setProfileOwner(String packageName, String ownerName, int userHandle);
     String getProfileOwner(int userHandle);
     String getProfileOwnerName(int userHandle);
+    void setProfileEnabled(in ComponentName who);
 
     boolean installCaCert(in byte[] certBuffer);
     void uninstallCaCert(in byte[] certBuffer);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9881428..a7d5606 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1417,15 +1417,38 @@
     // Standard intent broadcast actions (see action variable).
 
     /**
-     * Broadcast Action: Sent after the screen turns off.
+     * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes non-interactive which may have
+     * nothing to do with the screen turning off.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
     /**
-     * Broadcast Action: Sent after the screen turns on.
+     * Broadcast Action: Sent when the device wakes up and becomes interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes interactive which may have
+     * nothing to do with the screen turning on.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d24a472..d981cc1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1012,6 +1012,7 @@
      * @hide
      * @deprecated
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
 
@@ -1308,6 +1309,7 @@
      * something like a DPAD, not through touch or mouse.
      * @deprecated use {@link #FEATURE_LEANBACK} instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
 
@@ -1522,17 +1524,33 @@
     public abstract Intent getLaunchIntentForPackage(String packageName);
 
     /**
-     * Return an array of all of the secondary group-ids that have been
-     * assigned to a package.
-     *
-     * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name cannot be found on the system.
-     *
+     * Return a "good" intent to launch a front-door Leanback activity in a
+     * package, for use for example to implement an "open" button when browsing
+     * through packages. The current implementation will look for a main
+     * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+     * return null if no main leanback activities are found.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
+     * @param packageName The name of the package to inspect.
+     * @return Returns either a fully-qualified Intent that can be used to launch
+     *         the main Leanback activity in the package, or null if the package
+     *         does not contain such an activity.
+     */
+    public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+    /**
+     * Return an array of all of the secondary group-ids that have been assigned
+     * to a package.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *                    desired package.
-     *
-     * @return Returns an int array of the assigned gids, or null if there
-     * are none.
+     *            desired package.
+     * @return Returns an int array of the assigned gids, or null if there are
+     *         none.
      */
     public abstract int[] getPackageGids(String packageName)
             throws NameNotFoundException;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..4bea9ee 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@
     public static final int TYPE_ACCELEROMETER = 1;
 
     /**
+     * A constant string describing an accelerometer sensor type.
+     *
+     * @see #TYPE_ACCELEROMETER
+     */
+    public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+    /**
      * A constant describing a magnetic field sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -45,6 +52,13 @@
     public static final int TYPE_MAGNETIC_FIELD = 2;
 
     /**
+     * A constant string describing a magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+    /**
      * A constant describing an orientation sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -55,24 +69,58 @@
     @Deprecated
     public static final int TYPE_ORIENTATION = 3;
 
-    /** A constant describing a gyroscope sensor type.
+    /**
+     * A constant string describing an orientation sensor type.
+     *
+     * @see #TYPE_ORIENTATION
+     * @deprecated use {@link android.hardware.SensorManager#getOrientation
+     *             SensorManager.getOrientation()} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+    /**
+     * A constant describing a gyroscope sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details. */
     public static final int TYPE_GYROSCOPE = 4;
 
     /**
+     * A constant string describing a gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE
+     */
+    public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+    /**
      * A constant describing a light sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_LIGHT = 5;
 
-    /** A constant describing a pressure sensor type.
+    /**
+     * A constant string describing a light sensor type.
+     *
+     * @see #TYPE_LIGHT
+     */
+    public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+    /**
+     * A constant describing a pressure sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_PRESSURE = 6;
 
     /**
+     * A constant string describing a pressure sensor type.
+     *
+     * @see #TYPE_PRESSURE
+     */
+    public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+    /**
      * A constant describing a temperature sensor type
      *
      * @deprecated use
@@ -83,6 +131,17 @@
     public static final int TYPE_TEMPERATURE = 7;
 
     /**
+     * A constant string describing a temperature sensor type
+     *
+     * @see #TYPE_TEMPERATURE
+     * @deprecated use
+     *             {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+     *             Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+    /**
      * A constant describing a proximity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -90,6 +149,13 @@
     public static final int TYPE_PROXIMITY = 8;
 
     /**
+     * A constant string describing a proximity sensor type.
+     *
+     * @see #TYPE_PROXIMITY
+     */
+    public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+    /**
      * A constant describing a gravity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -97,6 +163,13 @@
     public static final int TYPE_GRAVITY = 9;
 
     /**
+     * A constant string describing a gravity sensor type.
+     *
+     * @see #TYPE_GRAVITY
+     */
+    public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+    /**
      * A constant describing a linear acceleration sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -104,6 +177,14 @@
     public static final int TYPE_LINEAR_ACCELERATION = 10;
 
     /**
+     * A constant string describing a linear acceleration sensor type.
+     *
+     * @see #TYPE_LINEAR_ACCELERATION
+     */
+    public static final String STRING_TYPE_LINEAR_ACCELERATION =
+        "android.sensor.linear_acceleration";
+
+    /**
      * A constant describing a rotation vector sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -111,18 +192,42 @@
     public static final int TYPE_ROTATION_VECTOR = 11;
 
     /**
+     * A constant string describing a rotation vector sensor type.
+     *
+     * @see #TYPE_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+    /**
      * A constant describing a relative humidity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_RELATIVE_HUMIDITY = 12;
 
-    /** A constant describing an ambient temperature sensor type.
+    /**
+     * A constant string describing a relative humidity sensor type
+     *
+     * @see #TYPE_RELATIVE_HUMIDITY
+     */
+    public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+    /**
+     * A constant describing an ambient temperature sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_AMBIENT_TEMPERATURE = 13;
 
     /**
+     * A constant string describing an ambient temperature sensor type.
+     *
+     * @see #TYPE_AMBIENT_TEMPERATURE
+     */
+    public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+        "android.sensor.ambient_temperature";
+
+    /**
      * A constant describing an uncalibrated magnetic field sensor type.
      * <p>
      * Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@
      * details.
      */
     public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+    /**
+     * A constant string describing an uncalibrated magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+        "android.sensor.magnetic_field_uncalibrated";
 
     /**
      * A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
      * details.
      */
-
     public static final int TYPE_GAME_ROTATION_VECTOR = 15;
 
     /**
+     * A constant string describing an uncalibrated rotation vector sensor type.
+     *
+     * @see #TYPE_GAME_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+        "android.sensor.game_rotation_vector";
+
+    /**
      * A constant describing an uncalibrated gyroscope sensor type.
      * <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
      * to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@
     public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
 
     /**
+     * A constant string describing an uncalibrated gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+        "android.sensor.gyroscope_uncalibrated";
+
+    /**
      * A constant describing a significant motion trigger sensor.
      * <p>
      * It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@
     public static final int TYPE_SIGNIFICANT_MOTION = 17;
 
     /**
+     * A constant string describing a significant motion trigger sensor.
+     *
+     * @see #TYPE_SIGNIFICANT_MOTION
+     */
+    public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+        "android.sensor.significant_motion";
+
+    /**
      * A constant describing a step detector sensor.
      * <p>
      * A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@
     public static final int TYPE_STEP_DETECTOR = 18;
 
     /**
+     * A constant string describing a step detector sensor.
+     *
+     * @see #TYPE_STEP_DETECTOR
+     */
+    public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+    /**
      * A constant describing a step counter sensor.
      * <p>
      * A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@
     public static final int TYPE_STEP_COUNTER = 19;
 
     /**
-     * A constant describing the geo-magnetic rotation vector.
+     * A constant string describing a step counter sensor.
+     *
+     * @see #TYPE_STEP_COUNTER
+     */
+    public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+    /**
+     * A constant describing a geo-magnetic rotation vector.
      * <p>
      * Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
      * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@
     public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
 
     /**
+     * A constant string describing a geo-magnetic rotation vector.
+     *
+     * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+        "android.sensor.geomagnetic_rotation_vector";
+
+    /**
+     * A constant describing a heart rate monitor.
+     * <p>
+     * A sensor that measures the heart rate in beats per minute.
+     * <p>
+     * value[0] represents the beats per minute when the measurement was taken.
+     * value[0] is 0 if the heart rate monitor could not measure the rate or the
+     * rate is 0 beat per minute.
+     */
+    public static final int TYPE_HEART_RATE = 21;
+
+    /**
+     * A constant string describing a heart rate monitor.
+     *
+     * @see #TYPE_HEART_RATE
+     */
+    public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+    /**
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@
             // added post 4.3
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_DETECTOR
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_COUNTER
-            REPORTING_MODE_CONTINUOUS, 5  // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_ON_CHANGE, 1  // SENSOR_TYPE_HEART_RATE_MONITOR
     };
 
     static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@
     private int     mMinDelay;
     private int     mFifoReservedEventCount;
     private int     mFifoMaxEventCount;
+    private String  mStringType;
+    private String  mRequiredPermission;
 
     Sensor() {
     }
@@ -401,6 +579,20 @@
         return mFifoMaxEventCount;
     }
 
+    /**
+     * @return The type of this sensor as a string.
+     */
+    public String getStringType() {
+        return mStringType;
+    }
+
+    /**
+     * @return The permission required to access this sensor. If empty, no permission is required.
+     */
+    public String getRequiredPermission() {
+        return mRequiredPermission;
+    }
+
     /** @hide */
     public int getHandle() {
         return mHandle;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/CaptureResultExtras.aidl
new file mode 100644
index 0000000..6587f02
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureResultExtras.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/CaptureResultExtras.java
new file mode 100644
index 0000000..e5c2c1c
--- /dev/null
+++ b/core/java/android/hardware/camera2/CaptureResultExtras.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class CaptureResultExtras implements Parcelable {
+    private int requestId;
+    private int subsequenceId;
+    private int afTriggerId;
+    private int precaptureTriggerId;
+    private long frameNumber;
+
+    public static final Parcelable.Creator<CaptureResultExtras> CREATOR =
+            new Parcelable.Creator<CaptureResultExtras>() {
+        @Override
+        public CaptureResultExtras createFromParcel(Parcel in) {
+            return new CaptureResultExtras(in);
+        }
+
+        @Override
+        public CaptureResultExtras[] newArray(int size) {
+            return new CaptureResultExtras[size];
+        }
+    };
+
+    private CaptureResultExtras(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(requestId);
+        dest.writeInt(subsequenceId);
+        dest.writeInt(afTriggerId);
+        dest.writeInt(precaptureTriggerId);
+        dest.writeLong(frameNumber);
+    }
+
+    public void readFromParcel(Parcel in) {
+        requestId = in.readInt();
+        subsequenceId = in.readInt();
+        afTriggerId = in.readInt();
+        precaptureTriggerId = in.readInt();
+        frameNumber = in.readLong();
+    }
+
+    public int getRequestId() {
+        return requestId;
+    }
+
+    public int getSubsequenceId() {
+        return subsequenceId;
+    }
+
+    public int getAfTriggerId() {
+        return afTriggerId;
+    }
+
+    public int getPrecaptureTriggerId() {
+        return precaptureTriggerId;
+    }
+
+    public long getFrameNumber() {
+        return frameNumber;
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 02a73d66..a14d38b 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.CaptureResultExtras;
 
 /** @hide */
 interface ICameraDeviceCallbacks
@@ -25,8 +26,9 @@
      * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
      */
 
-    oneway void onCameraError(int errorCode);
+    oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras);
     oneway void onCameraIdle();
-    oneway void onCaptureStarted(int requestId, long timestamp);
-    oneway void onResultReceived(int requestId, in CameraMetadataNative result);
+    oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
+    oneway void onResultReceived(in CameraMetadataNative result,
+                                 in CaptureResultExtras resultExtras);
 }
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 1936963..d77f3d1 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -20,6 +20,8 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.CaptureRequest;
 
+import android.hardware.camera2.LongParcelable;
+
 /** @hide */
 interface ICameraDeviceUser
 {
@@ -31,9 +33,13 @@
     // ints here are status_t
 
     // non-negative value is the requestId. negative value is status_t
-    int submitRequest(in CaptureRequest request, boolean streaming);
+    int submitRequest(in CaptureRequest request, boolean streaming,
+                      out LongParcelable lastFrameNumber);
 
-    int cancelRequest(int requestId);
+    int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
+                          out LongParcelable lastFrameNumber);
+
+    int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
 
     int deleteStream(int streamId);
 
@@ -46,5 +52,5 @@
 
     int waitUntilIdle();
 
-    int flush();
+    int flush(out LongParcelable lastFrameNumber);
 }
diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/LongParcelable.aidl
new file mode 100644
index 0000000..7d7e51b
--- /dev/null
+++ b/core/java/android/hardware/camera2/LongParcelable.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+parcelable LongParcelable;
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/LongParcelable.java
new file mode 100644
index 0000000..97b0631
--- /dev/null
+++ b/core/java/android/hardware/camera2/LongParcelable.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class LongParcelable implements Parcelable {
+    private long number;
+
+    public LongParcelable() {
+        this.number = 0;
+    }
+
+    public LongParcelable(long number) {
+        this.number = number;
+    }
+
+    public static final Parcelable.Creator<LongParcelable> CREATOR =
+            new Parcelable.Creator<LongParcelable>() {
+        @Override
+        public LongParcelable createFromParcel(Parcel in) {
+            return new LongParcelable(in);
+        }
+
+        @Override
+        public LongParcelable[] newArray(int size) {
+            return new LongParcelable[size];
+        }
+    };
+
+    private LongParcelable(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(number);
+    }
+
+    public void readFromParcel(Parcel in) {
+        number = in.readLong();
+    }
+
+    public long getNumber() {
+        return number;
+    }
+
+    public void setNumber(long number) {
+        this.number = number;
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index ecc461e..cd44b51 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,8 +21,10 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.LongParcelable;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.os.Handler;
@@ -33,10 +35,12 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.TreeSet;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -69,10 +73,24 @@
 
     private final String mCameraId;
 
+    /**
+     * A list tracking request and its expected last frame.
+     * Updated when calling ICameraDeviceUser methods.
+     */
+    private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>>
+            mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>();
+
+    /**
+     * An object tracking received frame numbers.
+     * Updated when receiving callbacks from ICameraDeviceCallbacks.
+     */
+    private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
+
     // Runnables for all state transitions, except error, which needs the
     // error code argument
 
     private final Runnable mCallOnOpened = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onOpened(CameraDevice.this);
@@ -81,6 +99,7 @@
     };
 
     private final Runnable mCallOnUnconfigured = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onUnconfigured(CameraDevice.this);
@@ -89,6 +108,7 @@
     };
 
     private final Runnable mCallOnActive = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onActive(CameraDevice.this);
@@ -97,6 +117,7 @@
     };
 
     private final Runnable mCallOnBusy = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onBusy(CameraDevice.this);
@@ -105,12 +126,14 @@
     };
 
     private final Runnable mCallOnClosed = new Runnable() {
+        @Override
         public void run() {
             mDeviceListener.onClosed(CameraDevice.this);
         }
     };
 
     private final Runnable mCallOnIdle = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onIdle(CameraDevice.this);
@@ -119,6 +142,7 @@
     };
 
     private final Runnable mCallOnDisconnected = new Runnable() {
+        @Override
         public void run() {
             if (!CameraDevice.this.isClosed()) {
                 mDeviceListener.onDisconnected(CameraDevice.this);
@@ -249,22 +273,26 @@
     @Override
     public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
             throws CameraAccessException {
-        return submitCaptureRequest(request, listener, handler, /*streaming*/false);
+        if (DEBUG) {
+            Log.d(TAG, "calling capture");
+        }
+        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
+        requestList.add(request);
+        return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
     }
 
     @Override
     public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
+        // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
         if (requests.isEmpty()) {
             Log.w(TAG, "Capture burst request list is empty, do nothing!");
             return -1;
         }
-        // TODO
-        throw new UnsupportedOperationException("Burst capture implemented yet");
-
+        return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
     }
 
-    private int submitCaptureRequest(CaptureRequest request, CaptureListener listener,
+    private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
             Handler handler, boolean repeating) throws CameraAccessException {
 
         // Need a valid handler, or current thread needs to have a looper, if
@@ -281,8 +309,13 @@
                 stopRepeating();
             }
 
+            LongParcelable lastFrameNumberRef = new LongParcelable();
             try {
-                requestId = mRemoteDevice.submitRequest(request, repeating);
+                requestId = mRemoteDevice.submitRequestList(requestList, repeating,
+                        /*out*/lastFrameNumberRef);
+                if (!repeating) {
+                    Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
+                }
             } catch (CameraRuntimeException e) {
                 throw e.asChecked();
             } catch (RemoteException e) {
@@ -290,12 +323,29 @@
                 return -1;
             }
             if (listener != null) {
-                mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request,
-                        handler, repeating));
+                mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
+                        requestList, handler, repeating));
             }
 
+            long lastFrameNumber = lastFrameNumberRef.getNumber();
+            /**
+             * If it's the first repeating request, then returned lastFrameNumber can be
+             * negative. Otherwise, it should always be non-negative.
+             */
+            if (((lastFrameNumber < 0) && (requestId > 0))
+                    || ((lastFrameNumber < 0) && (!repeating))) {
+                throw new AssertionError(String.format("returned bad frame number %d",
+                        lastFrameNumber));
+            }
             if (repeating) {
+                if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+                }
                 mRepeatingRequestId = requestId;
+            } else {
+                mFrameNumberRequestPairs.add(
+                        new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
             }
 
             if (mIdle) {
@@ -310,18 +360,20 @@
     @Override
     public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
             Handler handler) throws CameraAccessException {
-        return submitCaptureRequest(request, listener, handler, /*streaming*/true);
+        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
+        requestList.add(request);
+        return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
     }
 
     @Override
     public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
             Handler handler) throws CameraAccessException {
+        // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc.
         if (requests.isEmpty()) {
             Log.w(TAG, "Set Repeating burst request list is empty, do nothing!");
             return -1;
         }
-        // TODO
-        throw new UnsupportedOperationException("Burst capture implemented yet");
+        return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
     }
 
     @Override
@@ -340,7 +392,15 @@
                 }
 
                 try {
-                    mRemoteDevice.cancelRequest(requestId);
+                    LongParcelable lastFrameNumberRef = new LongParcelable();
+                    mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
+                    long lastFrameNumber = lastFrameNumberRef.getNumber();
+                    if ((lastFrameNumber < 0) && (requestId > 0)) {
+                        throw new AssertionError(String.format("returned bad frame number %d",
+                                lastFrameNumber));
+                    }
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
                 } catch (CameraRuntimeException e) {
                     throw e.asChecked();
                 } catch (RemoteException e) {
@@ -379,7 +439,17 @@
 
             mDeviceHandler.post(mCallOnBusy);
             try {
-                mRemoteDevice.flush();
+                LongParcelable lastFrameNumberRef = new LongParcelable();
+                mRemoteDevice.flush(/*out*/lastFrameNumberRef);
+                if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                    long lastFrameNumber = lastFrameNumberRef.getNumber();
+                    if (lastFrameNumber < 0) {
+                        Log.e(TAG, String.format("returned bad frame number %d", lastFrameNumber));
+                    }
+                    mFrameNumberRequestPairs.add(
+                            new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+                    mRepeatingRequestId = REQUEST_ID_NONE;
+                }
             } catch (CameraRuntimeException e) {
                 throw e.asChecked();
             } catch (RemoteException e) {
@@ -425,18 +495,18 @@
 
         private final boolean mRepeating;
         private final CaptureListener mListener;
-        private final CaptureRequest mRequest;
+        private final List<CaptureRequest> mRequestList;
         private final Handler mHandler;
 
-        CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler,
-                boolean repeating) {
+        CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList,
+                Handler handler, boolean repeating) {
             if (listener == null || handler == null) {
                 throw new UnsupportedOperationException(
                     "Must have a valid handler and a valid listener");
             }
             mRepeating = repeating;
             mHandler = handler;
-            mRequest = request;
+            mRequestList = new ArrayList<CaptureRequest>(requestList);
             mListener = listener;
         }
 
@@ -448,8 +518,24 @@
             return mListener;
         }
 
+        public CaptureRequest getRequest(int subsequenceId) {
+            if (subsequenceId >= mRequestList.size()) {
+                throw new IllegalArgumentException(
+                        String.format(
+                                "Requested subsequenceId %d is larger than request list size %d.",
+                                subsequenceId, mRequestList.size()));
+            } else {
+                if (subsequenceId < 0) {
+                    throw new IllegalArgumentException(String.format(
+                            "Requested subsequenceId %d is negative", subsequenceId));
+                } else {
+                    return mRequestList.get(subsequenceId);
+                }
+            }
+        }
+
         public CaptureRequest getRequest() {
-            return mRequest;
+            return getRequest(0);
         }
 
         public Handler getHandler() {
@@ -458,6 +544,105 @@
 
     }
 
+    /**
+     * This class tracks the last frame number for submitted requests.
+     */
+    public class FrameNumberTracker {
+
+        private long mCompletedFrameNumber = -1;
+        private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
+
+        private void update() {
+            Iterator<Long> iter = mFutureErrorSet.iterator();
+            while (iter.hasNext()) {
+                long errorFrameNumber = iter.next();
+                if (errorFrameNumber == mCompletedFrameNumber + 1) {
+                    mCompletedFrameNumber++;
+                    iter.remove();
+                } else {
+                    break;
+                }
+            }
+        }
+
+        /**
+         * This function is called every time when a result or an error is received.
+         * @param frameNumber: the frame number corresponding to the result or error
+         * @param isError: true if it is an error, false if it is not an error
+         */
+        public void updateTracker(long frameNumber, boolean isError) {
+            if (isError) {
+                mFutureErrorSet.add(frameNumber);
+            } else {
+                /**
+                 * HAL cannot send an OnResultReceived for frame N unless it knows for
+                 * sure that all frames prior to N have either errored out or completed.
+                 * So if the current frame is not an error, then all previous frames
+                 * should have arrived. The following line checks whether this holds.
+                 */
+                if (frameNumber != mCompletedFrameNumber + 1) {
+                    throw new AssertionError(String.format(
+                            "result frame number %d comes out of order",
+                            frameNumber));
+                }
+                mCompletedFrameNumber++;
+            }
+            update();
+        }
+
+        public long getCompletedFrameNumber() {
+            return mCompletedFrameNumber;
+        }
+
+    }
+
+    private void checkAndFireSequenceComplete() {
+        long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+        Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
+        while (iter.hasNext()) {
+            final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
+            if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
+
+                // remove request from mCaptureListenerMap
+                final int requestId = frameNumberRequestPair.getValue();
+                final CaptureListenerHolder holder;
+                synchronized (mLock) {
+                    int index = CameraDevice.this.mCaptureListenerMap.indexOfKey(requestId);
+                    holder = (index >= 0) ? CameraDevice.this.mCaptureListenerMap.valueAt(index)
+                            : null;
+                    if (holder != null) {
+                        CameraDevice.this.mCaptureListenerMap.removeAt(index);
+                    }
+                }
+                iter.remove();
+
+                // Call onCaptureSequenceCompleted
+                if (holder != null) {
+                    Runnable resultDispatch = new Runnable() {
+                        @Override
+                        public void run() {
+                            if (!CameraDevice.this.isClosed()){
+                                if (DEBUG) {
+                                    Log.d(TAG, String.format(
+                                            "fire sequence complete for request %d",
+                                            requestId));
+                                }
+
+                                holder.getListener().onCaptureSequenceCompleted(
+                                    CameraDevice.this,
+                                    requestId,
+                                    // TODO: this is problematic, crop long to int
+                                    frameNumberRequestPair.getKey().intValue());
+                            }
+                        }
+                    };
+                    holder.getHandler().post(resultDispatch);
+                }
+
+            }
+        }
+    }
+
     public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
         //
@@ -492,7 +677,7 @@
         }
 
         @Override
-        public void onCameraError(final int errorCode) {
+        public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
             Runnable r = null;
             if (isClosed()) return;
 
@@ -507,6 +692,7 @@
                     case ERROR_CAMERA_DEVICE:
                     case ERROR_CAMERA_SERVICE:
                         r = new Runnable() {
+                            @Override
                             public void run() {
                                 if (!CameraDevice.this.isClosed()) {
                                     mDeviceListener.onError(CameraDevice.this, errorCode);
@@ -517,6 +703,11 @@
                 }
                 CameraDevice.this.mDeviceHandler.post(r);
             }
+
+            // Fire onCaptureSequenceCompleted
+            mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
+            checkAndFireSequenceComplete();
+
         }
 
         @Override
@@ -535,7 +726,8 @@
         }
 
         @Override
-        public void onCaptureStarted(int requestId, final long timestamp) {
+        public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
+            int requestId = resultExtras.getRequestId();
             if (DEBUG) {
                 Log.d(TAG, "Capture started for id " + requestId);
             }
@@ -555,11 +747,12 @@
             // Dispatch capture start notice
             holder.getHandler().post(
                 new Runnable() {
+                    @Override
                     public void run() {
                         if (!CameraDevice.this.isClosed()) {
                             holder.getListener().onCaptureStarted(
                                 CameraDevice.this,
-                                holder.getRequest(),
+                                holder.getRequest(resultExtras.getSubsequenceId()),
                                 timestamp);
                         }
                     }
@@ -567,48 +760,18 @@
         }
 
         @Override
-        public void onResultReceived(int requestId, CameraMetadataNative result)
-                throws RemoteException {
+        public void onResultReceived(CameraMetadataNative result,
+                CaptureResultExtras resultExtras) throws RemoteException {
+            int requestId = resultExtras.getRequestId();
             if (DEBUG) {
                 Log.d(TAG, "Received result for id " + requestId);
             }
-            final CaptureListenerHolder holder;
+            final CaptureListenerHolder holder =
+                    CameraDevice.this.mCaptureListenerMap.get(requestId);
 
             Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
             boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
 
-            synchronized (mLock) {
-                // TODO: move this whole map into this class to make it more testable,
-                //        exposing the methods necessary like subscribeToRequest, unsubscribe..
-                // TODO: make class static class
-
-                holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
-
-                // Clean up listener once we no longer expect to see it.
-                if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
-                    CameraDevice.this.mCaptureListenerMap.remove(requestId);
-                }
-
-                // TODO: add 'capture sequence completed' callback to the
-                // service, and clean up repeating requests there instead.
-
-                // If we received a result for a repeating request and have
-                // prior repeating requests queued for deletion, remove those
-                // requests from mCaptureListenerMap.
-                if (holder != null && holder.isRepeating() && !quirkIsPartialResult
-                        && mRepeatingRequestIdDeletedList.size() > 0) {
-                    Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
-                    while (iter.hasNext()) {
-                        int deletedRequestId = iter.next();
-                        if (deletedRequestId < requestId) {
-                            CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId);
-                            iter.remove();
-                        }
-                    }
-                }
-
-            }
-
             // Check if we have a listener for this
             if (holder == null) {
                 return;
@@ -616,7 +779,7 @@
 
             if (isClosed()) return;
 
-            final CaptureRequest request = holder.getRequest();
+            final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
             final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
 
             Runnable resultDispatch = null;
@@ -651,6 +814,12 @@
             }
 
             holder.getHandler().post(resultDispatch);
+
+            // Fire onCaptureSequenceCompleted
+            if (!quirkIsPartialResult) {
+                mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
+                checkAndFireSequenceComplete();
+            }
         }
 
     }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 03fa1d5..cec90cd 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -58,16 +58,6 @@
     public abstract boolean isProximitySensorAvailable();
 
     /**
-     * Called by the power manager to blank all displays.
-     */
-    public abstract void blankAllDisplaysFromPowerManager();
-
-    /**
-     * Called by the power manager to unblank all displays.
-     */
-    public abstract void unblankAllDisplaysFromPowerManager();
-
-    /**
      * Returns information about the specified logical display.
      *
      * @param displayId The logical display id.
@@ -254,12 +244,10 @@
         void onStateChanged();
         void onProximityPositive();
         void onProximityNegative();
+        void onDisplayStateChange(int state); // one of the Display state constants
 
         void acquireSuspendBlocker();
         void releaseSuspendBlocker();
-
-        void blankAllDisplays();
-        void unblankAllDisplays();
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index 1f382e6..cd86cd8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -88,7 +88,7 @@
     }
 
     /**
-     * Send &lt;TextViewOn&gt; message.
+     * Send &lt;Text View On&gt; message.
      */
     public void sendTextViewOn() {
         try {
@@ -99,7 +99,7 @@
     }
 
     /**
-     * Send &lt;ImageViewOn&gt; message.
+     * Send &lt;Image View On&gt; message.
      */
     public void sendImageViewOn() {
         try {
@@ -110,6 +110,20 @@
     }
 
     /**
+     * Send &lt;Give Device Power Status&gt; message.
+     *
+     * @param address logical address of the device to send the message to, such as
+     *        {@link HdmiCec#ADDR_TV}.
+     */
+    public void sendGiveDevicePowerStatus(int address) {
+        try {
+            mService.sendGiveDevicePowerStatus(mBinder, address);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+        }
+    }
+
+    /**
      * Returns true if the TV or attached display is powered on.
      * <p>
      * The result of this method is only meaningful on playback devices (where the device
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index b5df131..ecdd345 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -33,6 +33,7 @@
     void sendInactiveSource(IBinder b);
     void sendImageViewOn(IBinder b);
     void sendTextViewOn(IBinder b);
+    void sendGiveDevicePowerStatus(IBinder b, int address);
     boolean isTvOn(IBinder b);
     void sendMessage(IBinder b, in HdmiCecMessage message);
 }
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 8be94d0..6a392dd 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -25,12 +25,18 @@
  * @hide Only for use within the system server.
  */
 public abstract class InputManagerInternal {
+    public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
     /**
-     * Sets information about the displays as needed by the input system.
-     * The input system should copy this information if required.
+     * Called by the display manager to set information about the displays as needed
+     * by the input system.  The input system must copy this information to retain it.
      */
     public abstract void setDisplayViewports(DisplayViewport defaultViewport,
             DisplayViewport externalTouchViewport);
 
-    public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+    /**
+     * Called by the power manager to tell the input manager whether it should start
+     * watching for wake events.
+     */
+    public abstract void setInteractive(boolean interactive);
 }
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 205a21d..6fdb0d0 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -18,8 +18,15 @@
 
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.util.Log;
+import android.util.ArrayMap;
 
+import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+
 
 /**
  * A class representing service information for network service discovery
@@ -27,11 +34,13 @@
  */
 public final class NsdServiceInfo implements Parcelable {
 
+    private static final String TAG = "NsdServiceInfo";
+
     private String mServiceName;
 
     private String mServiceType;
 
-    private DnsSdTxtRecord mTxtRecord;
+    private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<String, byte[]>();
 
     private InetAddress mHost;
 
@@ -41,10 +50,9 @@
     }
 
     /** @hide */
-    public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
+    public NsdServiceInfo(String sn, String rt) {
         mServiceName = sn;
         mServiceType = rt;
-        mTxtRecord = tr;
     }
 
     /** Get the service name */
@@ -67,16 +75,6 @@
         mServiceType = s;
     }
 
-    /** @hide */
-    public DnsSdTxtRecord getTxtRecord() {
-        return mTxtRecord;
-    }
-
-    /** @hide */
-    public void setTxtRecord(DnsSdTxtRecord t) {
-        mTxtRecord = new DnsSdTxtRecord(t);
-    }
-
     /** Get the host address. The host address is valid for a resolved service. */
     public InetAddress getHost() {
         return mHost;
@@ -97,14 +95,134 @@
         mPort = p;
     }
 
+    /** @hide */
+    public void setAttribute(String key, byte[] value) {
+        // Key must be printable US-ASCII, excluding =.
+        for (int i = 0; i < key.length(); ++i) {
+            char character = key.charAt(i);
+            if (character < 0x20 || character > 0x7E) {
+                throw new IllegalArgumentException("Key strings must be printable US-ASCII");
+            } else if (character == 0x3D) {
+                throw new IllegalArgumentException("Key strings must not include '='");
+            }
+        }
+
+        // Key length + value length must be < 255.
+        if (key.length() + (value == null ? 0 : value.length) >= 255) {
+            throw new IllegalArgumentException("Key length + value length must be < 255 bytes");
+        }
+
+        // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4.
+        if (key.length() > 9) {
+            Log.w(TAG, "Key lengths > 9 are discouraged: " + key);
+        }
+
+        // Check against total TXT record size limits.
+        // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2.
+        int txtRecordSize = getTxtRecordSize();
+        int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2;
+        if (futureSize > 1300) {
+            throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes");
+        } else if (futureSize > 400) {
+            Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur");
+        }
+
+        mTxtRecord.put(key, value);
+    }
+
+    /**
+     * Add a service attribute as a key/value pair.
+     *
+     * <p> Service attributes are included as DNS-SD TXT record pairs.
+     *
+     * <p> The key must be US-ASCII printable characters, excluding the '=' character.  Values may
+     * be UTF-8 strings or null.  The total length of key + value must be less than 255 bytes.
+     *
+     * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of
+     * {@link NsdServiceInfo}.  Calling {@link #setAttribute} twice with the same key will overwrite
+     * first value.
+     */
+    public void setAttribute(String key, String value) {
+        try {
+            setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new IllegalArgumentException("Value must be UTF-8");
+        }
+    }
+
+    /** Remove an attribute by key */
+    public void removeAttribute(String key) {
+        mTxtRecord.remove(key);
+    }
+
+    /**
+     * Retrive attributes as a map of String keys to byte[] values.
+     *
+     * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
+     * {@link #removeAttribute}.
+     */
+    public Map<String, byte[]> getAttributes() {
+        return Collections.unmodifiableMap(mTxtRecord);
+    }
+
+    private int getTxtRecordSize() {
+        int txtRecordSize = 0;
+        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+            txtRecordSize += 2;  // One for the length byte, one for the = between key and value.
+            txtRecordSize += entry.getKey().length();
+            byte[] value = entry.getValue();
+            txtRecordSize += value == null ? 0 : value.length;
+        }
+        return txtRecordSize;
+    }
+
+    /** @hide */
+    public byte[] getTxtRecord() {
+        int txtRecordSize = getTxtRecordSize();
+        if (txtRecordSize == 0) {
+            return null;
+        }
+
+        byte[] txtRecord = new byte[txtRecordSize];
+        int ptr = 0;
+        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+            String key = entry.getKey();
+            byte[] value = entry.getValue();
+
+            // One byte to record the length of this key/value pair.
+            txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1);
+
+            // The key, in US-ASCII.
+            // Note: use the StandardCharsets const here because it doesn't raise exceptions and we
+            // already know the key is ASCII at this point.
+            System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr,
+                    key.length());
+            ptr += key.length();
+
+            // US-ASCII '=' character.
+            txtRecord[ptr++] = (byte)'=';
+
+            // The value, as any raw bytes.
+            if (value != null) {
+                System.arraycopy(value, 0, txtRecord, ptr, value.length);
+                ptr += value.length;
+            }
+        }
+        return txtRecord;
+    }
+
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("name: ").append(mServiceName).
-            append("type: ").append(mServiceType).
-            append("host: ").append(mHost).
-            append("port: ").append(mPort).
-            append("txtRecord: ").append(mTxtRecord);
+        sb.append("name: ").append(mServiceName)
+                .append(", type: ").append(mServiceType)
+                .append(", host: ").append(mHost)
+                .append(", port: ").append(mPort);
+
+        byte[] txtRecord = getTxtRecord();
+        if (txtRecord != null) {
+            sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
+        }
         return sb.toString();
     }
 
@@ -117,14 +235,27 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mServiceName);
         dest.writeString(mServiceType);
-        dest.writeParcelable(mTxtRecord, flags);
         if (mHost != null) {
-            dest.writeByte((byte)1);
+            dest.writeInt(1);
             dest.writeByteArray(mHost.getAddress());
         } else {
-            dest.writeByte((byte)0);
+            dest.writeInt(0);
         }
         dest.writeInt(mPort);
+
+        // TXT record key/value pairs.
+        dest.writeInt(mTxtRecord.size());
+        for (String key : mTxtRecord.keySet()) {
+            byte[] value = mTxtRecord.get(key);
+            if (value != null) {
+                dest.writeInt(1);
+                dest.writeInt(value.length);
+                dest.writeByteArray(value);
+            } else {
+                dest.writeInt(0);
+            }
+            dest.writeString(key);
+        }
     }
 
     /** Implement the Parcelable interface */
@@ -134,15 +265,26 @@
                 NsdServiceInfo info = new NsdServiceInfo();
                 info.mServiceName = in.readString();
                 info.mServiceType = in.readString();
-                info.mTxtRecord = in.readParcelable(null);
 
-                if (in.readByte() == 1) {
+                if (in.readInt() == 1) {
                     try {
                         info.mHost = InetAddress.getByAddress(in.createByteArray());
                     } catch (java.net.UnknownHostException e) {}
                 }
 
                 info.mPort = in.readInt();
+
+                // TXT record key/value pairs.
+                int recordCount = in.readInt();
+                for (int i = 0; i < recordCount; ++i) {
+                    byte[] valueArray = null;
+                    if (in.readInt() == 1) {
+                        int valueLength = in.readInt();
+                        valueArray = new byte[valueLength];
+                        in.readByteArray(valueArray);
+                    }
+                    info.mTxtRecord.put(in.readString(), valueArray);
+                }
                 return info;
             }
 
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index be3c0cc..6c7b08d 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -40,8 +40,8 @@
     void wakeUp(long time);
     void goToSleep(long time, int reason);
     void nap(long time);
+    boolean isInteractive();
 
-    boolean isScreenOn();
     void reboot(boolean confirm, String reason, boolean wait);
     void shutdown(boolean confirm, boolean wait);
     void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a195200..f8d7c3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -601,21 +601,64 @@
     }
 
     /**
-      * Returns whether the screen is currently on.
+      * Returns true if the device is in an interactive state.
       * <p>
-      * Only indicates whether the screen is on.  The screen could be either bright or dim.
+      * For historical reasons, the name of this method refers to the power state of
+      * the screen but it actually describes the overall interactive state of
+      * the device.  This method has been replaced by {@link #isInteractive}.
       * </p><p>
-      * {@samplecode
-      * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-      * boolean isScreenOn = pm.isScreenOn();
-      * }
+      * The value returned by this method only indicates whether the device is
+      * in an interactive state which may have nothing to do with the screen being
+      * on or off.  To determine the actual state of the screen,
+      * use {@link android.view.Display#getState}.
       * </p>
       *
-      * @return whether the screen is on (bright or dim).
+      * @return True if the device is in an interactive state.
+      *
+      * @deprecated Use {@link #isInteractive} instead.
       */
+    @Deprecated
     public boolean isScreenOn() {
+        return isInteractive();
+    }
+
+    /**
+     * Returns true if the device is in an interactive state.
+     * <p>
+     * When this method returns true, the device is awake and ready to interact
+     * with the user (although this is not a guarantee that the user is actively
+     * interacting with the device just this moment).  The main screen is usually
+     * turned on while in this state.  Certain features, such as the proximity
+     * sensor, may temporarily turn off the screen while still leaving the device in an
+     * interactive state.  Note in particular that the device is still considered
+     * to be interactive while dreaming (since dreams can be interactive) but not
+     * when it is dozing or asleep.
+     * </p><p>
+     * When this method returns false, the device is dozing or asleep and must
+     * be awoken before it will become ready to interact with the user again.  The
+     * main screen is usually turned off while in this state.  Certain features,
+     * such as "ambient mode" may cause the main screen to remain on (albeit in a
+     * low power state) to display system-provided content while the device dozes.
+     * </p><p>
+     * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+     * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+     * whenever the interactive state of the device changes.  For historical reasons,
+     * the names of these broadcasts refer to the power state of the screen
+     * but they are actually sent in response to changes in the overall interactive
+     * state of the device, as described by this method.
+     * </p><p>
+     * Services may use the non-interactive state as a hint to conserve power
+     * since the user is not present.
+     * </p>
+     *
+     * @return True if the device is in an interactive state.
+     *
+     * @see android.content.Intent#ACTION_SCREEN_ON
+     * @see android.content.Intent#ACTION_SCREEN_OFF
+     */
+    public boolean isInteractive() {
         try {
-            return mService.isScreenOn();
+            return mService.isInteractive();
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index c947eda..995e396 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -372,7 +372,7 @@
             for (int i = 0; i < tries; i++) {
                 if (i > 0) {
                     try {
-                        Log.i("Zygote", "Zygote not up yet, sleeping...");
+                        Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
                         Thread.sleep(ZYGOTE_RETRY_MILLIS);
                     } catch (InterruptedException ex) {
                         throw new ZygoteStartFailedEx(ex);
@@ -707,6 +707,16 @@
             return primaryZygoteState;
         }
 
+        // TODO: Get rid of this. This is a temporary workaround until all the
+        // compilation related pieces for the dual zygote stack are ready.
+        // b/3647418.
+        if (System.getenv("ANDROID_SOCKET_" + SECONDARY_ZYGOTE_SOCKET) == null) {
+            Log.e(LOG_TAG, "Forcing app to primary zygote, secondary unavailable (ABI= " + abi + ")");
+            // Should be :
+            // throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
+            return primaryZygoteState;
+        }
+
         // The primary zygote didn't match. Try the secondary.
         if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
             secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 728c560..8aef9bd 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -492,7 +492,20 @@
         return profiles;
     }
 
-    /** @hide */
+    /**
+     * If the target user is a managed profile of the calling user or the caller
+     * is itself a managed profile, then this returns a badged copy of the given
+     * icon to be able to distinguish it from the original icon.
+     * <P>
+     * If the original drawable is not a BitmapDrawable, then the original
+     * drawable is returned.
+     * </P>
+     *
+     * @param icon The icon to badge.
+     * @param user The target user.
+     * @return A drawable that combines the original icon and a badge as
+     *         determined by the system.
+     */
     public Drawable getBadgedDrawableForUser(Drawable icon, UserHandle user) {
         int badgeResId = getBadgeResIdForUser(user.getIdentifier());
         if (badgeResId == 0) {
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index 05285a3..60bcc40 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -115,6 +115,7 @@
      * Default constructor.
      */
     public SearchIndexableData() {
+        locale = Locale.getDefault();
         enabled = true;
     }
 
@@ -124,8 +125,47 @@
      * @param ctx the Context
      */
     public SearchIndexableData(Context ctx) {
+        this();
         context = ctx;
-        locale = Locale.getDefault();
-        enabled = true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SearchIndexableData[context: ");
+        sb.append(context);
+        sb.append(", ");
+        sb.append("locale: ");
+        sb.append(locale);
+        sb.append(", ");
+        sb.append("enabled: ");
+        sb.append(enabled);
+        sb.append(", ");
+        sb.append("rank: ");
+        sb.append(rank);
+        sb.append(", ");
+        sb.append("key: ");
+        sb.append(key);
+        sb.append(", ");
+        sb.append("className: ");
+        sb.append(className);
+        sb.append(", ");
+        sb.append("packageName: ");
+        sb.append(packageName);
+        sb.append(", ");
+        sb.append("iconResId: ");
+        sb.append(iconResId);
+        sb.append(", ");
+        sb.append("intentAction: ");
+        sb.append(intentAction);
+        sb.append(", ");
+        sb.append("intentTargetPackage: ");
+        sb.append(intentTargetPackage);
+        sb.append(", ");
+        sb.append("intentTargetClass: ");
+        sb.append(intentTargetClass);
+        sb.append("]");
+
+        return sb.toString();
     }
 }
diff --git a/core/java/android/provider/SearchIndexableResource.java b/core/java/android/provider/SearchIndexableResource.java
index ba3bd4f..c807df2 100644
--- a/core/java/android/provider/SearchIndexableResource.java
+++ b/core/java/android/provider/SearchIndexableResource.java
@@ -48,6 +48,7 @@
      * @param iconResId the resource ID associated with the data.
      */
     public SearchIndexableResource(int rank, int xmlResId, String className, int iconResId) {
+        super();
         this.rank = rank;
         this.xmlResId = xmlResId;
         this.className = className;
@@ -62,4 +63,17 @@
     public SearchIndexableResource(Context context) {
         super(context);
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SearchIndexableResource[");
+        sb.append(super.toString());
+        sb.append(", ");
+        sb.append("xmlResId: ");
+        sb.append(xmlResId);
+        sb.append("]");
+
+        return sb.toString();
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index 1754dce..a8b4cfb0 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -35,7 +35,7 @@
     private static final String SETTINGS = "settings";
 
     /**
-     * Indexable references name.
+     * Indexable reference names.
      */
     public static final String INDEXABLES_XML_RES = "indexables_xml_res";
 
@@ -45,7 +45,7 @@
     public static final String INDEXABLES_XML_RES_PATH = SETTINGS + "/" + INDEXABLES_XML_RES;
 
     /**
-     * Indexable raw data name.
+     * Indexable raw data names.
      */
     public static final String INDEXABLES_RAW = "indexables_raw";
 
@@ -55,6 +55,16 @@
     public static final String INDEXABLES_RAW_PATH = SETTINGS + "/" + INDEXABLES_RAW;
 
     /**
+     * Non indexable data keys.
+     */
+    public static final String NON_INDEXABLES_KEYS = "non_indexables_key";
+
+    /**
+     * ContentProvider path for non indexable data keys.
+     */
+    public static final String NON_INDEXABLES_KEYS_PATH = SETTINGS + "/" + NON_INDEXABLES_KEYS;
+
+    /**
      * Indexable xml resources colums.
      */
     public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] {
@@ -114,6 +124,17 @@
     public static final int COLUMN_INDEX_RAW_INTENT_TARGET_CLASS = 11;
     public static final int COLUMN_INDEX_RAW_KEY = 12;
 
+    /**
+     * Indexable raw data colums.
+     */
+    public static final String[] NON_INDEXABLES_KEYS_COLUMNS = new String[] {
+            NonIndexableKey.COLUMN_KEY_VALUE      // 0
+    };
+
+    /**
+     * Non indexable data keys colums indices.
+     */
+    public static final int COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE = 0;
 
     /**
      * Constants related to a {@link SearchIndexableResource}.
@@ -165,7 +186,7 @@
         public static final String COLUMN_SUMMARY_OFF = "summaryOff";
 
         /**
-         * Entries associated with the raw data (when the data can can several values).
+         * Entries associated with the raw data (when the data can have several values).
          */
         public static final String COLUMN_ENTRIES = "entries";
 
@@ -175,7 +196,7 @@
         public static final String COLUMN_KEYWORDS = "keywords";
 
         /**
-         * Fragment's title associated with the raw data.
+         * Fragment or Activity title associated with the raw data.
          */
         public static final String COLUMN_SCREEN_TITLE = "screenTitle";
 
@@ -186,6 +207,24 @@
     }
 
     /**
+     * Constants related to a {@link SearchIndexableResource} and {@link SearchIndexableData}.
+     *
+     * This is a description of a data (thru its unique key) that cannot be indexed.
+     */
+    public static final class NonIndexableKey extends BaseColumns {
+        private NonIndexableKey() {
+        }
+
+        public static final String MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +
+                "/" + NON_INDEXABLES_KEYS;
+
+        /**
+         * Key for the non indexable data.
+         */
+        public static final String COLUMN_KEY_VALUE = "key";
+    }
+
+    /**
      * The base columns.
      */
     private static class BaseColumns {
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 2e358e4..9c8f6d0 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -69,6 +69,7 @@
 
     private static final int MATCH_RES_CODE = 1;
     private static final int MATCH_RAW_CODE = 2;
+    private static final int MATCH_NON_INDEXABLE_KEYS_CODE = 3;
 
     /**
      * Implementation is provided by the parent class.
@@ -82,6 +83,8 @@
                 MATCH_RES_CODE);
         mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_RAW_PATH,
                 MATCH_RAW_CODE);
+        mMatcher.addURI(mAuthority, SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH,
+                MATCH_NON_INDEXABLE_KEYS_CODE);
 
         // Sanity check our setup
         if (!info.exported) {
@@ -105,6 +108,8 @@
                 return queryXmlResources(null);
             case MATCH_RAW_CODE:
                 return queryRawData(null);
+            case MATCH_NON_INDEXABLE_KEYS_CODE:
+                return queryNonIndexableKeys(null);
             default:
                 throw new UnsupportedOperationException("Unknown Uri " + uri);
         }
@@ -113,7 +118,7 @@
     /**
      * Returns all {@link android.provider.SearchIndexablesContract.XmlResource}.
      *
-     * Those are usually xml resource ID to some {@link android.preference.PreferenceScreen}.
+     * Those are Xml resource IDs to some {@link android.preference.PreferenceScreen}.
      *
      * @param projection list of {@link android.provider.SearchIndexablesContract.XmlResource}
      *                   columns to put into the cursor. If {@code null} all supported columns
@@ -124,7 +129,7 @@
     /**
      * Returns all {@link android.provider.SearchIndexablesContract.RawData}.
      *
-     * Those are raw indexable data.
+     * Those are the raw indexable data.
      *
      * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns
      *                   to put into the cursor. If {@code null} all supported columns should be
@@ -132,6 +137,17 @@
      */
     public abstract Cursor queryRawData(String[] projection);
 
+    /**
+     * Returns all {@link android.provider.SearchIndexablesContract.NonIndexableKey}.
+     *
+     * Those are the non indexable data keys.
+     *
+     * @param projection list of {@link android.provider.SearchIndexablesContract.NonIndexableKey}
+     *                   columns to put into the cursor. If {@code null} all supported columns
+     *                   should be included.
+     */
+    public abstract Cursor queryNonIndexableKeys(String[] projection);
+
     @Override
     public String getType(Uri uri) {
         switch (mMatcher.match(uri)) {
@@ -139,14 +155,15 @@
                 return SearchIndexablesContract.XmlResource.MIME_TYPE;
             case MATCH_RAW_CODE:
                 return SearchIndexablesContract.RawData.MIME_TYPE;
+            case MATCH_NON_INDEXABLE_KEYS_CODE:
+                return SearchIndexablesContract.NonIndexableKey.MIME_TYPE;
             default:
                 throw new IllegalArgumentException("Unknown URI " + uri);
         }
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
      */
     @Override
     public final Uri insert(Uri uri, ContentValues values) {
@@ -154,8 +171,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
      */
     @Override
     public final int delete(Uri uri, String selection, String[] selectionArgs) {
@@ -163,8 +179,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
      */
     @Override
     public final int update(
diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java
new file mode 100644
index 0000000..233e0ca
--- /dev/null
+++ b/core/java/android/provider/TvContract.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.content.ContentUris;
+import android.net.Uri;
+
+/**
+ * <p>
+ * The contract between the TV provider and applications. Contains definitions for the supported
+ * URIs and columns.
+ * </p>
+ * <h3>Overview</h3>
+ * <p>
+ * TvContract defines a basic database of TV content metadata such as channel and program
+ * information. The information is stored in {@link Channels} and {@link Programs} tables.
+ * </p>
+ * <ul>
+ *     <li>A row in the {@link Channels} table represents information about a TV channel. The data
+ *         format can vary greatly from standard to standard or according to service provider, thus
+ *         the columns here are mostly comprised of basic entities that are usually seen to users
+ *         regardless of standard such as channel number and name.</li>
+ *     <li>A row in the {@link Programs} table represents a set of data describing a TV program such
+ *         as program title and start time.</li>
+ * </ul>
+ */
+public final class TvContract {
+    /** The authority for the TV provider. */
+    public static final String AUTHORITY = "com.android.tv";
+
+    /**
+     * Builds a URI that points to a specific channel.
+     *
+     * @param channelId The ID of the channel to point to.
+     */
+    public static final Uri buildChannelUri(long channelId) {
+        return ContentUris.withAppendedId(Channels.CONTENT_URI, channelId);
+    }
+
+    /**
+     * Builds a URI that points to a specific program.
+     *
+     * @param programId The ID of the program to point to.
+     */
+    public static final Uri buildProgramUri(long programId) {
+        return ContentUris.withAppendedId(Programs.CONTENT_URI, programId);
+    }
+
+    /**
+     * Builds a URI that points to a specific program the user watched.
+     *
+     * @param watchedProgramId The ID of the watched program to point to.
+     * @hide
+     */
+    public static final Uri buildWatchedProgramUri(long watchedProgramId) {
+        return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId);
+    }
+
+    private TvContract() {}
+
+    /**
+     * Common base for the tables of TV channels/programs.
+     */
+    public interface BaseTvColumns extends BaseColumns {
+        /**
+         * The name of the package that owns a row in each table.
+         * <p>
+         * The TV provider fills it in with the name of the package that provides the initial data
+         * of that row. If the package is later uninstalled, the rows it owns are automatically
+         * removed from the tables.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String PACKAGE_NAME = "package_name";
+    }
+
+    /** Column definitions for the TV channels table. */
+    public static final class Channels implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/channel");
+
+        /** The MIME type of a directory of TV channels. */
+        public static final String CONTENT_TYPE =
+                "vnd.android.cursor.dir/vnd.com.android.tv.channels";
+
+        /** The MIME type of a single TV channel. */
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/vnd.com.android.tv.channels";
+
+        /** A generic channel type. */
+        public static final int TYPE_OTHER = 0x0;
+
+        /** The special channel type used for pass-through inputs such as HDMI. */
+        public static final int TYPE_PASSTHROUGH = 0x00010000;
+
+        /** The channel type for DVB-T (terrestrial). */
+        public static final int TYPE_DVB_T = 0x00020000;
+
+        /** The channel type for DVB-T2 (terrestrial). */
+        public static final int TYPE_DVB_T2 = 0x00020001;
+
+        /** The channel type for DVB-S (satellite). */
+        public static final int TYPE_DVB_S = 0x00020100;
+
+        /** The channel type for DVB-S2 (satellite). */
+        public static final int TYPE_DVB_S2 = 0x00020101;
+
+        /** The channel type for DVB-C (cable). */
+        public static final int TYPE_DVB_C = 0x00020200;
+
+        /** The channel type for DVB-C2 (cable). */
+        public static final int TYPE_DVB_C2 = 0x00020201;
+
+        /** The channel type for DVB-H (handheld). */
+        public static final int TYPE_DVB_H = 0x00020300;
+
+        /** The channel type for DVB-SH (satellite). */
+        public static final int TYPE_DVB_SH = 0x00020400;
+
+        /** The channel type for ATSC (terrestrial/cable). */
+        public static final int TYPE_ATSC = 0x00030000;
+
+        /** The channel type for ATSC 2.0. */
+        public static final int TYPE_ATSC_2_0 = 0x00030001;
+
+        /** The channel type for ATSC-M/H (mobile/handheld). */
+        public static final int TYPE_ATSC_M_H = 0x00030100;
+
+        /** The channel type for ISDB-T (terrestrial). */
+        public static final int TYPE_ISDB_T = 0x00040000;
+
+        /** The channel type for ISDB-Tb (Brazil). */
+        public static final int TYPE_ISDB_TB = 0x00040100;
+
+        /** The channel type for ISDB-S (satellite). */
+        public static final int TYPE_ISDB_S = 0x00040200;
+
+        /** The channel type for ISDB-C (cable). */
+        public static final int TYPE_ISDB_C = 0x00040300;
+
+        /** The channel type for 1seg (handheld). */
+        public static final int TYPE_1SEG = 0x00040400;
+
+        /** The channel type for DTMB (terrestrial). */
+        public static final int TYPE_DTMB = 0x00050000;
+
+        /** The channel type for CMMB (handheld). */
+        public static final int TYPE_CMMB = 0x00050100;
+
+        /** The channel type for T-DMB (terrestrial). */
+        public static final int TYPE_T_DMB = 0x00060000;
+
+        /** The channel type for S-DMB (satellite). */
+        public static final int TYPE_S_DMB = 0x00060100;
+
+        /**
+         * The name of the TV input service that provides this TV channel.
+         * <p>
+         * This is a required field.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String SERVICE_NAME = "service_name";
+
+        /**
+         * The predefined type of this TV channel.
+         * <p>
+         * This is used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the current
+         * channel conforms to.
+         * </p><p>
+         * This is a required field.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String TYPE = "type";
+
+        /**
+         * The transport stream ID as appeared in various broadcast standards.
+         * <p>
+         * This is not a required field but if provided, can significantly increase the accuracy of
+         * channel identification.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String TRANSPORT_STREAM_ID = "transport_stream_id";
+
+        /**
+         * The channel number that is displayed to the user.
+         * <p>
+         * The format can vary depending on broadcast standard and product specification.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String DISPLAY_NUMBER = "display_number";
+
+        /**
+         * The channel name that is displayed to the user.
+         * <p>
+         * A call sign is a good candidate to use for this purpose but any name that helps the user
+         * recognize the current channel will be enough. Can also be empty depending on broadcast
+         * standard.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String DISPLAY_NAME = "display_name";
+
+        /**
+         * The description of this TV channel.
+         * <p>
+         * Can be empty initially.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String DESCRIPTION = "description";
+
+        /**
+         * The flag indicating whether this TV channel is browsable or not.
+         * <p>
+         * A value of 1 indicates the channel is included in the channel list that applications use
+         * to browse channels, a value of 0 indicates the channel is not included in the list. If
+         * not specified, this value is set to 1 by default.
+         * </p><p>
+         * Type: INTEGER (boolean)
+         * </p>
+         */
+        public static final String BROWSABLE = "browsable";
+
+        /**
+         * Generic data used by individual TV input services.
+         * <p>
+         * Type: BLOB
+         * </p>
+         */
+        public static final String DATA = "data";
+
+
+        /**
+         * The version number of this row entry used by TV input services.
+         * <p>
+         * This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are
+         * coming from a TV broadcast.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String VERSION_NUMBER = "version_number";
+
+        private Channels() {}
+    }
+
+    /** Column definitions for the TV programs table. */
+    public static final class Programs implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/program");
+
+        /** The MIME type of a directory of TV programs. */
+        public static final String CONTENT_TYPE =
+                "vnd.android.cursor.dir/vnd.com.android.tv.programs";
+
+        /** The MIME type of a single TV program. */
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/vnd.com.android.tv.programs";
+
+        /**
+         * The ID of the TV channel that contains this TV program.
+         * <p>
+         * This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+         * </p><p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String CHANNEL_ID = "channel_id";
+
+        /**
+         * The title of this TV program.
+         * <p>
+         * Type: TEXT
+         * </p>
+         **/
+        public static final String TITLE = "title";
+
+        /**
+         * The start time of this TV program, in milliseconds since the epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+
+        /**
+         * The end time of this TV program, in milliseconds since the epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+
+        /**
+         * The description of this TV program that is displayed to the user by default.
+         * <p>
+         * The maximum length of this field is 256 characters.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String DESCRIPTION = "description";
+
+        /**
+         * The detailed, lengthy description of this TV program that is displayed only when the user
+         * wants to see more information.
+         * <p>
+         * TV input services should leave this field empty if they have no additional
+         * details beyond {@link #DESCRIPTION}.
+         * </p><p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String LONG_DESCRIPTION = "long_description";
+
+        /**
+         * Generic data used by TV input services.
+         * <p>
+         * Type: BLOB
+         * </p>
+         */
+        public static final String DATA = "data";
+
+        /**
+         * The version number of this row entry used by TV input services.
+         * <p>
+         * This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+         * broadcast.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String VERSION_NUMBER = "version_number";
+
+        private Programs() {}
+    }
+
+    /**
+     * Column definitions for the TV programs that the user watched. Applications do not have access
+     * to this table.
+     *
+     * @hide
+     */
+    public static final class WatchedPrograms implements BaseColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI =
+                Uri.parse("content://" + AUTHORITY + "/watched_program");
+
+        /** The MIME type of a directory of watched programs. */
+        public static final String CONTENT_TYPE =
+                "vnd.android.cursor.dir/vnd.com.android.tv.watched_programs";
+
+        /** The MIME type of a single item in this table. */
+        public static final String CONTENT_ITEM_TYPE =
+                "vnd.android.cursor.item/vnd.com.android.tv.watched_programs";
+
+        /**
+         * The UTC time that the user started watching this TV program, in milliseconds since the
+         * epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
+
+        /**
+         * The UTC time that the user stopped watching this TV program, in milliseconds since the
+         * epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
+
+        /**
+         * The channel ID that contains this TV program.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String CHANNEL_ID = "channel_id";
+
+        /**
+         * The title of this TV program.
+         * <p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String TITLE = "title";
+
+        /**
+         * The start time of this TV program, in milliseconds since the epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+
+        /**
+         * The end time of this TV program, in milliseconds since the epoch.
+         * <p>
+         * Type: INTEGER (long)
+         * </p>
+         */
+        public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+
+        /**
+         * The description of this TV program.
+         * <p>
+         * Type: TEXT
+         * </p>
+         */
+        public static final String DESCRIPTION = "description";
+
+        private WatchedPrograms() {}
+    }
+}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index de9eeff0..2303d65 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -789,10 +789,20 @@
             return;
         }
 
-        // start it up
-        if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
-        mStarted = true;
-        onDreamingStarted();
+        // We need to defer calling onDreamingStarted until after onWindowAttached,
+        // which is posted to the handler by addView, so we post onDreamingStarted
+        // to the handler also.  Need to watch out here in case detach occurs before
+        // this callback is invoked.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mWindow != null) {
+                    if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+                    mStarted = true;
+                    onDreamingStarted();
+                }
+            }
+        });
     }
 
     private void safelyFinish() {
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index c6a14f2..10e2073 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -57,7 +57,7 @@
  * successful callback is the client usable.
  * <p>
  * After successful connection, the list of all available voices can be obtained
- * by calling the {@link TextToSpeechClient#getEngineStatus() method. The client can
+ * by calling the {@link TextToSpeechClient#getEngineStatus()} method. The client can
  * choose a voice using some custom heuristic and build a {@link RequestConfig} object
  * using {@link RequestConfig.Builder}, or can use one of the common heuristics found
  * in ({@link RequestConfigHelper}.
@@ -69,7 +69,7 @@
  * {@link ConnectionCallbacks#onEngineStatusChange} with new set of available voices as argument.
  * In response, the client HAVE to recreate all {@link RequestConfig} instances in use.
  */
-public final class TextToSpeechClient {
+public class TextToSpeechClient {
     private static final String TAG = TextToSpeechClient.class.getSimpleName();
 
     private final Object mLock = new Object();
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90625d8..90e4177 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -87,6 +87,34 @@
         return 0;
     }
 
+    @Override
+    public int hashCode() {
+        return mId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof TvInputInfo)) {
+            return false;
+        }
+
+        TvInputInfo obj = (TvInputInfo) o;
+        return mId.equals(obj.mId)
+                && mService.serviceInfo.packageName.equals(obj.mService.serviceInfo.packageName)
+                && mService.serviceInfo.name.equals(obj.mService.serviceInfo.name);
+    }
+
+    @Override
+    public String toString() {
+        return "TvInputInfo{id=" + mId
+                + ", pkg=" + mService.serviceInfo.packageName
+                + ", service=" + mService.serviceInfo.name + "}";
+    }
+
     /**
      * Used to package this object into a {@link Parcel}.
      *
diff --git a/core/java/android/view/AnimationRenderStats.aidl b/core/java/android/view/AnimationRenderStats.aidl
new file mode 100644
index 0000000..4599708
--- /dev/null
+++ b/core/java/android/view/AnimationRenderStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable AnimationRenderStats;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index d3f63b4..d7a913d 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@
     public static final int TYPE_VIRTUAL = 5;
 
     /**
+     * Display state: The display state is unknown.
+     *
+     * @see #getState
+     */
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * Display state: The display is off.
+     *
+     * @see #getState
+     */
+    public static final int STATE_OFF = 1;
+
+    /**
+     * Display state: The display is on.
+     *
+     * @see #getState
+     */
+    public static final int STATE_ON = 2;
+
+    /**
+     * Display state: The display is dozing in a low-power state; it may be showing
+     * system-provided content while the device is in a non-interactive state.
+     *
+     * @see #getState
+     * @see android.os.PowerManager#isInteractive
+     */
+    public static final int STATE_DOZING = 3;
+
+    /**
      * Internal method to create a display.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
      * or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -630,6 +660,19 @@
     }
 
     /**
+     * Gets the state of the display, such as whether it is on or off.
+     *
+     * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+     * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+     */
+    public int getState() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+        }
+    }
+
+    /**
      * Returns true if the specified UID has access to this display.
      * @hide
      */
@@ -720,5 +763,22 @@
                 return Integer.toString(type);
         }
     }
-}
 
+    /**
+     * @hide
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+            case STATE_UNKNOWN:
+                return "UNKNOWN";
+            case STATE_OFF:
+                return "OFF";
+            case STATE_ON:
+                return "ON";
+            case STATE_DOZING:
+                return "DOZING";
+            default:
+                return Integer.toString(state);
+        }
+    }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 7fd7b83..b0fe0fa 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@
     public float physicalYDpi;
 
     /**
+     * The state of the display, such as {@link android.view.Display#STATE_ON}.
+     */
+    public int state;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@
                 && logicalDensityDpi == other.logicalDensityDpi
                 && physicalXDpi == other.physicalXDpi
                 && physicalYDpi == other.physicalYDpi
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -280,6 +286,7 @@
         logicalDensityDpi = other.logicalDensityDpi;
         physicalXDpi = other.physicalXDpi;
         physicalYDpi = other.physicalYDpi;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -307,6 +314,7 @@
         logicalDensityDpi = source.readInt();
         physicalXDpi = source.readFloat();
         physicalYDpi = source.readFloat();
+        state = source.readInt();
         ownerUid = source.readInt();
         ownerPackageName = source.readString();
     }
@@ -335,6 +343,7 @@
         dest.writeInt(logicalDensityDpi);
         dest.writeFloat(physicalXDpi);
         dest.writeFloat(physicalYDpi);
+        dest.writeInt(state);
         dest.writeInt(ownerUid);
         dest.writeString(ownerPackageName);
     }
@@ -431,7 +440,7 @@
         sb.append(smallestNominalAppHeight);
         sb.append(", ");
         sb.append(refreshRate);
-        sb.append(" fps, rotation");
+        sb.append(" fps, rotation ");
         sb.append(rotation);
         sb.append(", density ");
         sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ");
+        sb.append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/core/java/android/view/FrameStats.java b/core/java/android/view/FrameStats.java
new file mode 100644
index 0000000..541b336
--- /dev/null
+++ b/core/java/android/view/FrameStats.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This is the base class for frame statistics.
+ */
+public abstract class FrameStats {
+    /**
+     * Undefined time.
+     */
+    public static final long UNDEFINED_TIME_NANO = -1;
+
+    protected long mRefreshPeriodNano;
+    protected long[] mFramesPresentedTimeNano;
+
+    /**
+     * Gets the refresh period of the display hosting the window(s) for
+     * which these statistics apply.
+     *
+     * @return The refresh period in nanoseconds.
+     */
+    public final long getRefreshPeriodNano() {
+        return mRefreshPeriodNano;
+    }
+
+    /**
+     * Gets the number of frames for which there is data.
+     *
+     * @return The number of frames.
+     */
+    public final int getFrameCount() {
+        return mFramesPresentedTimeNano != null
+                ? mFramesPresentedTimeNano.length : 0;
+    }
+
+    /**
+     * Gets the start time of the interval for which these statistics
+     * apply. The start interval is the time when the first frame was
+     * presented.
+     *
+     * @return The start time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if there is no frame data.
+     */
+    public final long getStartTimeNano() {
+        if (getFrameCount() <= 0) {
+            return UNDEFINED_TIME_NANO;
+        }
+        return mFramesPresentedTimeNano[0];
+    }
+
+    /**
+     * Gets the end time of the interval for which these statistics
+     * apply. The end interval is the time when the last frame was
+     * presented.
+     *
+     * @return The end time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if there is no frame data.
+     */
+    public final long getEndTimeNano() {
+        if (getFrameCount() <= 0) {
+            return UNDEFINED_TIME_NANO;
+        }
+        return mFramesPresentedTimeNano[mFramesPresentedTimeNano.length - 1];
+    }
+
+    /**
+     * Get the time a frame at a given index was presented.
+     *
+     * @param index The frame index.
+     * @return The presented time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if the frame is not presented yet.
+     */
+    public final long getFramePresentedTimeNano(int index) {
+        if (mFramesPresentedTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesPresentedTimeNano[index];
+    }
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8ec07ef..3670eed 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -50,7 +50,6 @@
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
-    void dispatchScreenState(boolean on);
 
     /**
      * Tell the window that it is either gaining or losing focus.  Keep it up
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8f542bb..7d13399 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -37,6 +37,7 @@
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.IInputFilter;
+import android.view.WindowContentFrameStats;
 
 /**
  * System private interface to the window manager.
@@ -233,4 +234,25 @@
      * Device is in safe mode.
      */
     boolean isSafeModeEnabled();
+
+    /**
+     * Enables the screen if all conditions are met.
+     */
+    void enableScreenIfNeeded();
+
+    /**
+     * Clears the frame statistics for a given window.
+     *
+     * @param token The window token.
+     * @return Whether the frame statistics were cleared.
+     */
+    boolean clearWindowContentFrameStats(IBinder token);
+
+    /**
+     * Gets the content frame statistics for a given window.
+     *
+     * @param token The window token.
+     * @return The frame statistics or null if the window does not exist.
+     */
+    WindowContentFrameStats getWindowContentFrameStats(IBinder token);
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c183f08..c3f429c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1166,7 +1166,11 @@
 
     /**
      * This mask is set if the device woke because of this key event.
+     *
+     * @deprecated This flag will never be set by the system since the system
+     * consumes all wake keys itself.
      */
+    @Deprecated
     public static final int FLAG_WOKE_HERE = 0x1;
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5a8d2c8..2d55a01 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -20,7 +20,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.view.Surface;
 import android.os.IBinder;
 import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
@@ -59,6 +58,11 @@
     private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
     private static native void nativeSetLayerStack(long nativeObject, int layerStack);
 
+    private static native boolean nativeClearContentFrameStats(long nativeObject);
+    private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
+    private static native boolean nativeClearAnimationFrameStats();
+    private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
+
     private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
     private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -357,6 +361,24 @@
         nativeSetTransparentRegionHint(mNativeObject, region);
     }
 
+    public boolean clearContentFrameStats() {
+        checkNotReleased();
+        return nativeClearContentFrameStats(mNativeObject);
+    }
+
+    public boolean getContentFrameStats(WindowContentFrameStats outStats) {
+        checkNotReleased();
+        return nativeGetContentFrameStats(mNativeObject, outStats);
+    }
+
+    public static boolean clearAnimationFrameStats() {
+        return nativeClearAnimationFrameStats();
+    }
+
+    public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
+        return nativeGetAnimationFrameStats(outStats);
+    }
+
     /**
      * Sets an alpha value for the entire Surface.  This value is combined with the
      * per-pixel alpha.  It may be used with opaque Surfaces.
@@ -542,7 +564,6 @@
         return nativeGetBuiltInDisplay(builtInDisplayId);
     }
 
-
     /**
      * Copy the current screen contents into the provided {@link Surface}
      *
@@ -592,7 +613,6 @@
         screenshot(display, consumer, 0, 0, 0, 0, true, false);
     }
 
-
     /**
      * Copy the current screen contents into a bitmap and return it.
      *
@@ -626,8 +646,8 @@
     }
 
     /**
-     * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
-     * Surfaces in the screenshot.
+     * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but
+     * includes all Surfaces in the screenshot.
      *
      * @param width The desired width of the returned bitmap; the raw
      * screen will be scaled down to this size.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1ecc3c6..1429837 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -55,16 +55,19 @@
     private int mWidth, mHeight;
     private long mNativeProxy;
     private boolean mInitialized = false;
+    private RenderNode mRootNode;
 
     ThreadedRenderer(boolean translucent) {
         mNativeProxy = nCreateProxy(translucent);
+        mRootNode = RenderNode.create("RootNode");
+        mRootNode.setClipToBounds(false);
     }
 
     @Override
     void destroy(boolean full) {
         mInitialized = false;
         updateEnabledState(null);
-        nDestroyCanvas(mNativeProxy);
+        nDestroyCanvasAndSurface(mNativeProxy);
     }
 
     private void updateEnabledState(Surface surface) {
@@ -127,6 +130,7 @@
     void setup(int width, int height) {
         mWidth = width;
         mHeight = height;
+        mRootNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
         nSetup(mNativeProxy, width, height);
     }
 
@@ -165,10 +169,7 @@
     public void repeatLastDraw() {
     }
 
-    @Override
-    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
-        attachInfo.mIgnoreDirtyState = true;
-        attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
         view.mPrivateFlags |= View.PFLAG_DRAWN;
 
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
@@ -176,26 +177,38 @@
         view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
 
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-        RenderNode displayList = view.getDisplayList();
+        HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
+        callbacks.onHardwarePostDraw(canvas);
+        canvas.drawDisplayList(view.getDisplayList());
+        callbacks.onHardwarePostDraw(canvas);
+        mRootNode.end(canvas);
         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
 
         view.mRecreateDisplayList = false;
+    }
+
+    @Override
+    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
+        attachInfo.mIgnoreDirtyState = true;
+        attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+
+        updateRootDisplayList(view, callbacks);
 
         if (dirty == null) {
             dirty = NULL_RECT;
         }
-        nDrawDisplayList(mNativeProxy, displayList.getNativeDisplayList(),
+        nDrawDisplayList(mNativeProxy, mRootNode.getNativeDisplayList(),
                 dirty.left, dirty.top, dirty.right, dirty.bottom);
     }
 
     @Override
     void detachFunctor(long functor) {
-        nDetachFunctor(mNativeProxy, functor);
+        // no-op, we never attach functors to need to detach them
     }
 
     @Override
     void attachFunctor(AttachInfo attachInfo, long functor) {
-        nAttachFunctor(mNativeProxy, functor);
+        invokeFunctor(functor, true);
     }
 
     @Override
@@ -287,10 +300,8 @@
     private static native void nDrawDisplayList(long nativeProxy, long displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
-    private static native void nDestroyCanvas(long nativeProxy);
+    private static native void nDestroyCanvasAndSurface(long nativeProxy);
 
-    private static native void nAttachFunctor(long nativeProxy, long functor);
-    private static native void nDetachFunctor(long nativeProxy, long functor);
     private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
 
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9761f1a..f44cc87 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2968,12 +2968,6 @@
     private boolean mLastIsOpaque;
 
     /**
-     * Convenience value to check for float values that are close enough to zero to be considered
-     * zero.
-     */
-    private static final float NONZERO_EPSILON = .001f;
-
-    /**
      * The distance in pixels from the left edge of this view's parent
      * to the left edge of this view.
      * {@hide}
@@ -8790,11 +8784,6 @@
                             && !pointInView(event.getX(), event.getY()))) {
                 mSendingHoverAccessibilityEvents = false;
                 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                // If the window does not have input focus we take away accessibility
-                // focus as soon as the user stop hovering over the view.
-                if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) {
-                    getViewRootImpl().setAccessibilityFocus(null, null);
-                }
             }
         }
 
@@ -17139,8 +17128,8 @@
             // If the screen is off assume the animation start time is now instead of
             // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time
             // would cause the animation to start when the screen turns back on
-            if (mAttachInfo != null && !mAttachInfo.mScreenOn &&
-                    animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
+            if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
+                    && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
                 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
             }
             animation.reset();
@@ -19119,7 +19108,7 @@
      * A set of information given to a view when it is attached to its parent
      * window.
      */
-    static class AttachInfo {
+    final static class AttachInfo {
         interface Callbacks {
             void playSoundEffect(int effectId);
             boolean performHapticFeedback(int effectId, boolean always);
@@ -19182,7 +19171,14 @@
         boolean mHardwareAccelerationRequested;
         HardwareRenderer mHardwareRenderer;
 
-        boolean mScreenOn;
+        /**
+         * The state of the display to which the window is attached, as reported
+         * by {@link Display#getState()}.  Note that the display state constants
+         * declared by {@link Display} do not exactly line up with the screen state
+         * constants declared by {@link View} (there are more display states than
+         * screen states).
+         */
+        int mDisplayState = Display.STATE_UNKNOWN;
 
         /**
          * Scale factor used by the compatibility mode
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 65ac50d..ef22def 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -37,6 +37,8 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Bundle;
@@ -134,6 +136,7 @@
     final Context mContext;
     final IWindowSession mWindowSession;
     final Display mDisplay;
+    final DisplayManager mDisplayManager;
     final String mBasePackageName;
 
     final int[] mTmpLocation = new int[2];
@@ -370,9 +373,7 @@
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
         mChoreographer = Choreographer.getInstance();
-
-        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mAttachInfo.mScreenOn = powerManager.isScreenOn();
+        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
     }
 
@@ -427,6 +428,10 @@
         synchronized (this) {
             if (mView == null) {
                 mView = view;
+
+                mAttachInfo.mDisplayState = mDisplay.getState();
+                mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+
                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                 mFallbackEventHandler.setView(view);
                 mWindowAttributes.copyFrom(attrs);
@@ -797,18 +802,43 @@
         scheduleTraversals();
     }
 
-    void handleScreenStateChange(boolean on) {
-        if (on != mAttachInfo.mScreenOn) {
-            mAttachInfo.mScreenOn = on;
-            if (mView != null) {
-                mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
-            }
-            if (on) {
-                mFullRedrawNeeded = true;
-                scheduleTraversals();
+    private final DisplayListener mDisplayListener = new DisplayListener() {
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (mView != null && mDisplay.getDisplayId() == displayId) {
+                final int oldDisplayState = mAttachInfo.mDisplayState;
+                final int newDisplayState = mDisplay.getState();
+                if (oldDisplayState != newDisplayState) {
+                    mAttachInfo.mDisplayState = newDisplayState;
+                    if (oldDisplayState != Display.STATE_UNKNOWN) {
+                        final int oldScreenState = toViewScreenState(oldDisplayState);
+                        final int newScreenState = toViewScreenState(newDisplayState);
+                        if (oldScreenState != newScreenState) {
+                            mView.dispatchScreenStateChanged(newScreenState);
+                        }
+                        if (oldDisplayState == Display.STATE_OFF) {
+                            // Draw was suppressed so we need to for it to happen here.
+                            mFullRedrawNeeded = true;
+                            scheduleTraversals();
+                        }
+                    }
+                }
             }
         }
-    }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+        }
+
+        private int toViewScreenState(int displayState) {
+            return displayState == Display.STATE_OFF ?
+                    View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
+        }
+    };
 
     @Override
     public void requestFitSystemWindows() {
@@ -2174,10 +2204,7 @@
             mResizePaint.setAlpha(mResizeAlpha);
             canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
         }
-        // TODO: this
-        if (!HardwareRenderer.sUseRenderThread) {
-            drawAccessibilityFocusedDrawableIfNeeded(canvas);
-        }
+        drawAccessibilityFocusedDrawableIfNeeded(canvas);
     }
 
     /**
@@ -2247,7 +2274,7 @@
     }
 
     private void performDraw() {
-        if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
+        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
             return;
         }
 
@@ -2873,6 +2900,8 @@
             mInputChannel = null;
         }
 
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+
         unscheduleTraversals();
     }
 
@@ -2952,7 +2981,6 @@
     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
     private final static int MSG_UPDATE_CONFIGURATION = 18;
     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
-    private final static int MSG_DISPATCH_SCREEN_STATE = 20;
     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
     private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
     private final static int MSG_INVALIDATE_WORLD = 23;
@@ -2999,8 +3027,6 @@
                     return "MSG_UPDATE_CONFIGURATION";
                 case MSG_PROCESS_INPUT_EVENTS:
                     return "MSG_PROCESS_INPUT_EVENTS";
-                case MSG_DISPATCH_SCREEN_STATE:
-                    return "MSG_DISPATCH_SCREEN_STATE";
                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
                 case MSG_DISPATCH_DONE_ANIMATING:
@@ -3214,11 +3240,6 @@
                 }
                 updateConfiguration(config, false);
             } break;
-            case MSG_DISPATCH_SCREEN_STATE: {
-                if (mView != null) {
-                    handleScreenStateChange(msg.arg1 == 1);
-                }
-            } break;
             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
                 setAccessibilityFocus(null, null);
             } break;
@@ -5795,12 +5816,6 @@
         mHandler.sendMessage(msg);
     }
 
-    public void dispatchScreenStateChange(boolean on) {
-        Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
-        msg.arg1 = on ? 1 : 0;
-        mHandler.sendMessage(msg);
-    }
-
     public void dispatchGetNewSurface() {
         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
         mHandler.sendMessage(msg);
@@ -6139,14 +6154,6 @@
         }
 
         @Override
-        public void dispatchScreenState(boolean on) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.dispatchScreenStateChange(on);
-            }
-        }
-
-        @Override
         public void dispatchGetNewSurface() {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index b05225b..4730e59 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -56,10 +56,8 @@
  *
  * @hide
  */
-public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener,
-        VolumeController
-{
-    private static final String TAG = "VolumePanel";
+public class VolumePanel extends Handler implements VolumeController {
+    private static final String TAG = VolumePanel.class.getSimpleName();
     private static boolean LOGD = false;
 
     /**
@@ -187,7 +185,7 @@
             this.iconMuteRes = iconMuteRes;
             this.show = show;
         }
-    };
+    }
 
     // List of stream types and their order
     private static final StreamResources[] STREAMS = {
@@ -238,6 +236,7 @@
             cleanUp();
         }
 
+        @Override
         public void onDismiss(DialogInterface unused) {
             mContext.unregisterReceiver(this);
             cleanUp();
@@ -253,14 +252,14 @@
     }
 
 
-    public VolumePanel(final Context context, AudioService volumeService) {
+    public VolumePanel(Context context, AudioService volumeService) {
         mContext = context;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mAudioService = volumeService;
 
         // For now, only show master volume if master volume is supported
-        boolean useMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
+        final Resources res = context.getResources();
+        final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
         if (useMasterVolume) {
             for (int i = 0; i < STREAMS.length; i++) {
                 StreamResources streamRes = STREAMS[i];
@@ -268,21 +267,8 @@
             }
         }
 
-        LayoutInflater inflater = (LayoutInflater) context
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View view = mView = inflater.inflate(R.layout.volume_adjust, null);
-        mView.setOnTouchListener(new View.OnTouchListener() {
-            public boolean onTouch(View v, MotionEvent event) {
-                resetTimeout();
-                return false;
-            }
-        });
-        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
-        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
-        mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
-        mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
-
-        mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
+        mDialog = new Dialog(context) {
+            @Override
             public boolean onTouchEvent(MotionEvent event) {
                 if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
                         sConfirmSafeVolumeDialog == null) {
@@ -292,47 +278,65 @@
                 return false;
             }
         };
-        mDialog.setTitle("Volume control"); // No need to localize
-        mDialog.setContentView(mView);
+
+        // Change some window properties
+        final Window window = mDialog.getWindow();
+        final LayoutParams lp = window.getAttributes();
+        lp.token = null;
+        // Offset from the top
+        lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
+        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+        lp.windowAnimations = R.style.Animation_VolumePanel;
+        window.setAttributes(lp);
+        window.setGravity(Gravity.TOP);
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
+                | LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+
+        mDialog.setCanceledOnTouchOutside(true);
+        mDialog.setContentView(R.layout.volume_adjust);
         mDialog.setOnDismissListener(new OnDismissListener() {
+            @Override
             public void onDismiss(DialogInterface dialog) {
                 mActiveStreamType = -1;
                 mAudioManager.forceVolumeControlStream(mActiveStreamType);
             }
         });
-        // Change some window properties
-        Window window = mDialog.getWindow();
-        window.setGravity(Gravity.TOP);
-        LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        // Offset from the top
-        lp.y = mContext.getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
-        lp.width = LayoutParams.WRAP_CONTENT;
-        lp.height = LayoutParams.WRAP_CONTENT;
-        window.setAttributes(lp);
-        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+
+        mDialog.create();
+
+        mView = window.findViewById(R.id.content);
+        mView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                resetTimeout();
+                return false;
+            }
+        });
+
+        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
+        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
+        mMoreButton = mView.findViewById(R.id.expand_button);
+        mDivider = mView.findViewById(R.id.expand_button_divider);
 
         mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
-
+        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
+
+        // If we don't want to show multiple volumes, hide the settings button
+        // and divider.
         mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
-        // If we don't want to show multiple volumes, hide the settings button and divider
         if (!mShowCombinedVolumes) {
             mMoreButton.setVisibility(View.GONE);
             mDivider.setVisibility(View.GONE);
         } else {
-            mMoreButton.setOnClickListener(this);
+            mMoreButton.setOnClickListener(mClickListener);
         }
 
-        boolean masterVolumeOnly = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
-        boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useVolumeKeySounds);
-
+        final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
+        final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
         mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
 
         listenToRingerMode();
@@ -347,7 +351,7 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         mContext.registerReceiver(new BroadcastReceiver() {
-
+            @Override
             public void onReceive(Context context, Intent intent) {
                 final String action = intent.getAction();
 
@@ -400,17 +404,21 @@
     }
 
     private void createSliders() {
-        LayoutInflater inflater = (LayoutInflater) mContext
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        final Resources res = mContext.getResources();
+        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+
         mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
-        Resources res = mContext.getResources();
+
         for (int i = 0; i < STREAMS.length; i++) {
             StreamResources streamRes = STREAMS[i];
-            int streamType = streamRes.streamType;
+
+            final int streamType = streamRes.streamType;
             if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
                 streamRes = StreamResources.RingerStream;
             }
-            StreamControl sc = new StreamControl();
+
+            final StreamControl sc = new StreamControl();
             sc.streamType = streamType;
             sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
             sc.group.setTag(sc);
@@ -421,10 +429,10 @@
             sc.iconMuteRes = streamRes.iconMuteRes;
             sc.icon.setImageResource(sc.iconRes);
             sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
-            int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
+            final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
             sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
-            sc.seekbarView.setOnSeekBarChangeListener(this);
+            sc.seekbarView.setOnSeekBarChangeListener(mSeekListener);
             sc.seekbarView.setTag(sc);
             mStreamControls.put(streamType, sc);
         }
@@ -433,7 +441,7 @@
     private void reorderSliders(int activeStreamType) {
         mSliderGroup.removeAllViews();
 
-        StreamControl active = mStreamControls.get(activeStreamType);
+        final StreamControl active = mStreamControls.get(activeStreamType);
         if (active == null) {
             Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
             mActiveStreamType = -1;
@@ -486,10 +494,6 @@
         }
     }
 
-    private boolean isExpanded() {
-        return mMoreButton.getVisibility() != View.VISIBLE;
-    }
-
     private void expand() {
         final int count = mSliderGroup.getChildCount();
         for (int i = 0; i < count; i++) {
@@ -527,6 +531,7 @@
         obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
     }
 
+    @Override
     public void postRemoteVolumeChanged(int streamType, int flags) {
         if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -538,6 +543,7 @@
         obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget();
     }
 
+    @Override
     public void postRemoteSliderVisibility(boolean visible) {
         obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED,
                 AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget();
@@ -554,6 +560,7 @@
      * as a request to update the volume), the application will likely set a new volume. If the UI
      * is still up, we need to refresh the display to show this new value.
      */
+    @Override
     public void postHasNewRemotePlaybackInfo() {
         if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return;
         // don't create or prevent resources to be freed, if they disappear, this update came too
@@ -733,7 +740,7 @@
             int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
             mAudioManager.forceVolumeControlStream(stream);
-            mDialog.setContentView(mView);
+
             // Showing dialog - use collapsed state
             if (mShowCombinedVolumes) {
                 collapse();
@@ -865,6 +872,7 @@
                         .setMessage(com.android.internal.R.string.safe_media_volume_warning)
                         .setPositiveButton(com.android.internal.R.string.yes,
                                             new DialogInterface.OnClickListener() {
+                            @Override
                             public void onClick(DialogInterface dialog, int which) {
                                 mAudioService.disableSafeMediaVolume();
                             }
@@ -1021,39 +1029,48 @@
         sendMessage(obtainMessage(MSG_TIMEOUT));
     }
 
-    public void onProgressChanged(SeekBar seekBar, int progress,
-            boolean fromUser) {
-        final Object tag = seekBar.getTag();
-        if (fromUser && tag instanceof StreamControl) {
-            StreamControl sc = (StreamControl) tag;
-            if (getStreamVolume(sc.streamType) != progress) {
-                setStreamVolume(sc.streamType, progress, 0);
+    private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            final Object tag = seekBar.getTag();
+            if (fromUser && tag instanceof StreamControl) {
+                StreamControl sc = (StreamControl) tag;
+                if (getStreamVolume(sc.streamType) != progress) {
+                    setStreamVolume(sc.streamType, progress, 0);
+                }
+            }
+            resetTimeout();
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            final Object tag = seekBar.getTag();
+            if (tag instanceof StreamControl) {
+                StreamControl sc = (StreamControl) tag;
+                // Because remote volume updates are asynchronous, AudioService
+                // might have received a new remote volume value since the
+                // finger adjusted the slider. So when the progress of the
+                // slider isn't being tracked anymore, adjust the slider to the
+                // last "published" remote volume value, so the UI reflects the
+                // actual volume.
+                if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
+                    seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
+                }
             }
         }
-        resetTimeout();
-    }
+    };
 
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-        final Object tag = seekBar.getTag();
-        if (tag instanceof StreamControl) {
-            StreamControl sc = (StreamControl) tag;
-            // because remote volume updates are asynchronous, AudioService might have received
-            // a new remote volume value since the finger adjusted the slider. So when the
-            // progress of the slider isn't being tracked anymore, adjust the slider to the last
-            // "published" remote volume value, so the UI reflects the actual volume.
-            if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
-                seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
+    private final View.OnClickListener mClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (v == mMoreButton) {
+                expand();
             }
+            resetTimeout();
         }
-    }
-
-    public void onClick(View v) {
-        if (v == mMoreButton) {
-            expand();
-        }
-        resetTimeout();
-    }
+    };
 }
diff --git a/core/java/android/view/WindowAnimationFrameStats.aidl b/core/java/android/view/WindowAnimationFrameStats.aidl
new file mode 100644
index 0000000..77f544b
--- /dev/null
+++ b/core/java/android/view/WindowAnimationFrameStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable WindowAnimationFrameStats;
diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java
new file mode 100644
index 0000000..c60b96c
--- /dev/null
+++ b/core/java/android/view/WindowAnimationFrameStats.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains window animation frame statistics. For example, a window
+ * animation is usually performed when the application is transitioning from one
+ * activity to another. The frame statistics are a snapshot for the time interval
+ * from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
+ * <p>
+ * The key idea is that in order to provide a smooth user experience the system should
+ * run window animations at a specific time interval obtained by calling {@link
+ * #getRefreshPeriodNano()}. If the system does not render a frame every refresh
+ * period the user will see irregular window transitions. The time when the frame was
+ * actually presented on the display by calling {@link #getFramePresentedTimeNano(int)}.
+ */
+public final class WindowAnimationFrameStats extends FrameStats implements Parcelable {
+    /**
+     * @hide
+     */
+    public WindowAnimationFrameStats() {
+        /* do nothing */
+    }
+
+    /**
+     * Initializes this isntance.
+     *
+     * @param refreshPeriodNano The display refresh period.
+     * @param framesPresentedTimeNano The presented frame times.
+     *
+     * @hide
+     */
+    public void init(long refreshPeriodNano, long[] framesPresentedTimeNano) {
+        mRefreshPeriodNano = refreshPeriodNano;
+        mFramesPresentedTimeNano = framesPresentedTimeNano;
+    }
+
+    private WindowAnimationFrameStats(Parcel parcel) {
+        mRefreshPeriodNano = parcel.readLong();
+        mFramesPresentedTimeNano = parcel.createLongArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeLong(mRefreshPeriodNano);
+        parcel.writeLongArray(mFramesPresentedTimeNano);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("WindowAnimationFrameStats[");
+        builder.append("frameCount:" + getFrameCount());
+        builder.append(", fromTimeNano:" + getStartTimeNano());
+        builder.append(", toTimeNano:" + getEndTimeNano());
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static final Creator<WindowAnimationFrameStats> CREATOR =
+            new Creator<WindowAnimationFrameStats>() {
+                @Override
+                public WindowAnimationFrameStats createFromParcel(Parcel parcel) {
+                    return new WindowAnimationFrameStats(parcel);
+                }
+
+                @Override
+                public WindowAnimationFrameStats[] newArray(int size) {
+                    return new WindowAnimationFrameStats[size];
+                }
+            };
+}
diff --git a/core/java/android/view/WindowContentFrameStats.aidl b/core/java/android/view/WindowContentFrameStats.aidl
new file mode 100644
index 0000000..aa9c2d6
--- /dev/null
+++ b/core/java/android/view/WindowContentFrameStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable WindowContentFrameStats;
diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java
new file mode 100644
index 0000000..c6da2fb
--- /dev/null
+++ b/core/java/android/view/WindowContentFrameStats.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains window content frame statistics. For example, a window content
+ * is rendred in frames when a view is scrolled. The frame statistics are a snapshot
+ * for the time interval from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}.
+ * <p>
+ * The key idea is that in order to provide a smooth user experience an application
+ * has to draw a frame at a specific time interval obtained by calling {@link
+ * #getRefreshPeriodNano()}. If the application does not render a frame every refresh
+ * period the user will see irregular UI transitions.
+ * </p>
+ * <p>
+ * An application posts a frame for presentation by synchronously rendering its contents
+ * in a buffer which is then posted or posting a buffer to which the application is
+ * asychronously rendering the content via GL. After the frame is posted and rendered
+ * (potentially asynchronosly) it is presented to the user. The time a frame was posted
+ * can be obtained via {@link #getFramePostedTimeNano(int)}, the time a frame content
+ * was rendered and ready for dsiplay (GL case) via {@link #getFrameReadyTimeNano(int)},
+ * and the time a frame was presented on the screen via {@link #getFramePresentedTimeNano(int)}.
+ * </p>
+ */
+public final class WindowContentFrameStats extends FrameStats implements Parcelable {
+    private long[] mFramesPostedTimeNano;
+    private long[] mFramesReadyTimeNano;
+
+    /**
+     * @hide
+     */
+    public WindowContentFrameStats() {
+        /* do nothing */
+    }
+
+    /**
+     * Initializes this isntance.
+     *
+     * @param refreshPeriodNano The display refresh period.
+     * @param framesPostedTimeNano The times in milliseconds for when the frame contents were posted.
+     * @param framesPresentedTimeNano The times in milliseconds for when the frame contents were presented.
+     * @param framesReadyTimeNano The times in milliseconds for when the frame contents were ready to be presented.
+     *
+     * @hide
+     */
+    public void init(long refreshPeriodNano, long[] framesPostedTimeNano,
+            long[] framesPresentedTimeNano, long[] framesReadyTimeNano) {
+        mRefreshPeriodNano = refreshPeriodNano;
+        mFramesPostedTimeNano = framesPostedTimeNano;
+        mFramesPresentedTimeNano = framesPresentedTimeNano;
+        mFramesReadyTimeNano = framesReadyTimeNano;
+    }
+
+    private WindowContentFrameStats(Parcel parcel) {
+        mRefreshPeriodNano = parcel.readLong();
+        mFramesPostedTimeNano = parcel.createLongArray();
+        mFramesPresentedTimeNano = parcel.createLongArray();
+        mFramesReadyTimeNano = parcel.createLongArray();
+    }
+
+    /**
+     * Get the time a frame at a given index was posted by the producer (e.g. the application).
+     * It is either explicitly set or defaulted to the time when the render buffer was posted.
+     * <p>
+     * <strong>Note:</strong> A frame can be posted and still it contents being rendered
+     * asynchronously in GL. To get the time the frame content was completely rendered and
+     * ready to display call {@link #getFrameReadyTimeNano(int)}.
+     * </p>
+     *
+     * @param index The frame index.
+     * @return The posted time in nanoseconds.
+     */
+    public long getFramePostedTimeNano(int index) {
+        if (mFramesPostedTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesPostedTimeNano[index];
+    }
+
+    /**
+     * Get the time a frame at a given index was ready for presentation.
+     * <p>
+     * <strong>Note:</strong> A frame can be posted and still it contents being rendered
+     * asynchronously in GL. In such a case this is the time when the frame contents were
+     * completely rendered.
+     * </p>
+     *
+     * @param index The frame index.
+     * @return The ready time in nanoseconds or {@link #UNDEFINED_TIME_NANO}
+     *         if the frame is not ready yet.
+     */
+    public long getFrameReadyTimeNano(int index) {
+        if (mFramesReadyTimeNano == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mFramesReadyTimeNano[index];
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeLong(mRefreshPeriodNano);
+        parcel.writeLongArray(mFramesPostedTimeNano);
+        parcel.writeLongArray(mFramesPresentedTimeNano);
+        parcel.writeLongArray(mFramesReadyTimeNano);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("WindowContentFrameStats[");
+        builder.append("frameCount:" + getFrameCount());
+        builder.append(", fromTimeNano:" + getStartTimeNano());
+        builder.append(", toTimeNano:" + getEndTimeNano());
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<WindowContentFrameStats> CREATOR =
+            new Creator<WindowContentFrameStats>() {
+                @Override
+                public WindowContentFrameStats createFromParcel(Parcel parcel) {
+                    return new WindowContentFrameStats(parcel);
+                }
+
+                @Override
+                public WindowContentFrameStats[] newArray(int size) {
+                    return new WindowContentFrameStats[size];
+                }
+            };
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..032a82f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -49,7 +49,7 @@
 public interface WindowManager extends ViewManager {
     /**
      * Exception that is thrown when trying to add view whose
-     * {@link WindowManager.LayoutParams} {@link WindowManager.LayoutParams#token}
+     * {@link LayoutParams} {@link LayoutParams#token}
      * is invalid.
      */
     public static class BadTokenException extends RuntimeException {
@@ -173,7 +173,6 @@
          * @see #TYPE_SEARCH_BAR
          * @see #TYPE_PHONE
          * @see #TYPE_SYSTEM_ALERT
-         * @see #TYPE_KEYGUARD
          * @see #TYPE_TOAST
          * @see #TYPE_SYSTEM_OVERLAY
          * @see #TYPE_PRIORITY_PHONE
@@ -197,7 +196,6 @@
             @ViewDebug.IntToString(from = TYPE_SEARCH_BAR, to = "TYPE_SEARCH_BAR"),
             @ViewDebug.IntToString(from = TYPE_PHONE, to = "TYPE_PHONE"),
             @ViewDebug.IntToString(from = TYPE_SYSTEM_ALERT, to = "TYPE_SYSTEM_ALERT"),
-            @ViewDebug.IntToString(from = TYPE_KEYGUARD, to = "TYPE_KEYGUARD"),
             @ViewDebug.IntToString(from = TYPE_TOAST, to = "TYPE_TOAST"),
             @ViewDebug.IntToString(from = TYPE_SYSTEM_OVERLAY, to = "TYPE_SYSTEM_OVERLAY"),
             @ViewDebug.IntToString(from = TYPE_PRIORITY_PHONE, to = "TYPE_PRIORITY_PHONE"),
@@ -341,13 +339,13 @@
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
-        
+
         /**
          * Window type: keyguard window.
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
-        
+
         /**
          * Window type: transient notifications.
          * In multiuser systems shows only on the owning user's window.
@@ -610,7 +608,10 @@
          * screen is pressed, you will receive this first touch event.  Usually
          * the first touch event is consumed by the system since the user can
          * not see what they are pressing on.
+         *
+         * @deprecated This flag has no effect.
          */
+        @Deprecated
         public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
         
         /** Window flag: as long as this window is visible to the user, keep
@@ -913,7 +914,6 @@
          */
         public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
 
-
         /**
          * Various behavioral options/flags.  Default is none.
          * 
@@ -1087,6 +1087,14 @@
         public static final int PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR = 0x00000200;
 
         /**
+         * Flag whether the current window is a keyguard window, meaning that it will hide all other
+         * windows behind it except for windows with flag {@link #FLAG_SHOW_WHEN_LOCKED} set.
+         * Further, this can only be set by {@link LayoutParams#TYPE_STATUS_BAR}.
+         * {@hide}
+         */
+        public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index bd203c8..c9be54d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -90,8 +90,7 @@
     public final static int FLAG_FILTERED = 0x04000000;
     public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
 
-    public final static int FLAG_WOKE_HERE = 0x10000000;
-    public final static int FLAG_BRIGHT_HERE = 0x20000000;
+    public final static int FLAG_INTERACTIVE = 0x20000000;
     public final static int FLAG_PASS_TO_USER = 0x40000000;
 
     // Flags used for indicating whether the internal and/or external input devices
@@ -744,11 +743,10 @@
      * because it's the most fragile.
      * @param event The key event.
      * @param policyFlags The policy flags associated with the key.
-     * @param isScreenOn True if the screen is already on
      *
      * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
     /**
      * Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -761,7 +759,7 @@
      *
      * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
@@ -1007,6 +1005,14 @@
     public void dismissKeyguardLw();
 
     /**
+     * Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
+     * returns true as soon as we know that Keyguard is disabled.
+     *
+     * @return true if the keyguard has drawn.
+     */
+    public boolean isKeyguardDrawnLw();
+
+    /**
      * Given an orientation constant, returns the appropriate surface rotation,
      * taking into account sensors, docking mode, rotation lock, and other factors.
      *
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 4dd8dcb..5b9372d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -163,6 +163,19 @@
     }
 
     /**
+     * Gets the root {@link AccessibilityNodeInfo} in a given window.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @param windowId The window id.
+     * @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
+     */
+    public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
+        return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID, false,
+                AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
+    }
+
+    /**
      * Gets the info for a window.
      *
      * @param connectionId The id of a connection for interacting with the system.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a6904f71..9d10930 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -77,6 +77,9 @@
     public static final int ACTIVE_WINDOW_ID = UNDEFINED_ITEM_ID;
 
     /** @hide */
+    public static final int ANY_WINDOW_ID = -2;
+
+    /** @hide */
     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
 
     /** @hide */
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index fe3e5c6..b6570cc 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -57,4 +57,6 @@
 
     void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
             boolean touchExplorationEnabled);
+
+    IBinder getWindowToken(int windowId);
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 81d36a4..85168fd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1691,6 +1691,9 @@
      * thread of this WebView. Care is therefore required to maintain thread
      * safety.</li>
      * <li> The Java object's fields are not accessible.</li>
+     * <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#L}
+     * and above, methods of injected Java objects are enumerable from
+     * JavaScript.</li>
      * </ul>
      *
      * @param object the Java object to inject into this WebView's JavaScript
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 00b2c13..d6fa05a 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1991,7 +1991,16 @@
             , '\u0669',
             // Extended Arabic-Indic
             '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8'
-            , '\u06f9'
+            , '\u06f9',
+            // Hindi and Marathi (Devanagari script)
+            '\u0966', '\u0967', '\u0968', '\u0969', '\u096a', '\u096b', '\u096c', '\u096d', '\u096e'
+            , '\u096f',
+            // Bengali
+            '\u09e6', '\u09e7', '\u09e8', '\u09e9', '\u09ea', '\u09eb', '\u09ec', '\u09ed', '\u09ee'
+            , '\u09ef',
+            // Kannada
+            '\u0ce6', '\u0ce7', '\u0ce8', '\u0ce9', '\u0cea', '\u0ceb', '\u0cec', '\u0ced', '\u0cee'
+            , '\u0cef'
     };
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5e4c143..a7278da 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -714,19 +714,19 @@
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowColor:
-                    shadowcolor = a.getInt(attr, 0);
+                    shadowcolor = appearance.getInt(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowDx:
-                    dx = a.getFloat(attr, 0);
+                    dx = appearance.getFloat(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowDy:
-                    dy = a.getFloat(attr, 0);
+                    dy = appearance.getFloat(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowRadius:
-                    r = a.getFloat(attr, 0);
+                    r = appearance.getFloat(attr, 0);
                     break;
                 }
             }
diff --git a/core/java/com/android/internal/notification/PeopleNotificationScorer.java b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
new file mode 100644
index 0000000..efb5f63
--- /dev/null
+++ b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
@@ -0,0 +1,227 @@
+/*
+* Copyright (C) 2014 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.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.LruCache;
+import android.util.Slog;
+
+/**
+ * This {@link NotificationScorer} attempts to validate people references.
+ * Also elevates the priority of real people.
+ */
+public class PeopleNotificationScorer implements NotificationScorer {
+    private static final String TAG = "PeopleNotificationScorer";
+    private static final boolean DBG = false;
+
+    private static final boolean ENABLE_PEOPLE_SCORER = true;
+    private static final String SETTING_ENABLE_PEOPLE_SCORER = "people_scorer_enabled";
+    private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
+    private static final int MAX_PEOPLE = 10;
+    private static final int PEOPLE_CACHE_SIZE = 200;
+    // see NotificationManagerService
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+
+    protected boolean mEnabled;
+    private Context mContext;
+
+    // maps raw person handle to resolved person object
+    private LruCache<String, LookupResult> mPeopleCache;
+
+    private float findMaxContactScore(Bundle extras) {
+        if (extras == null) {
+            return 0f;
+        }
+
+        final String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
+        if (people == null || people.length == 0) {
+            return 0f;
+        }
+
+        float rank = 0f;
+        for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
+            final String handle = people[personIdx];
+            if (TextUtils.isEmpty(handle)) continue;
+
+            LookupResult lookupResult = mPeopleCache.get(handle);
+            if (lookupResult == null || lookupResult.isExpired()) {
+                final Uri uri = Uri.parse(handle);
+                if ("tel".equals(uri.getScheme())) {
+                    if (DBG) Slog.w(TAG, "checking telephone URI: " + handle);
+                    lookupResult = lookupPhoneContact(handle, uri.getSchemeSpecificPart());
+                } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
+                    if (DBG) Slog.w(TAG, "checking lookup URI: " + handle);
+                    lookupResult = resolveContactsUri(handle, uri);
+                } else {
+                    if (DBG) Slog.w(TAG, "unsupported URI " + handle);
+                }
+            } else {
+                if (DBG) Slog.w(TAG, "using cached lookupResult: " + lookupResult.mId);
+            }
+            if (lookupResult != null) {
+                rank = Math.max(rank, lookupResult.getRank());
+            }
+        }
+        return rank;
+    }
+
+    private LookupResult lookupPhoneContact(final String handle, final String number) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+                    Uri.encode(number));
+            c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DBG) Slog.w(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        mPeopleCache.put(handle, lookupResult);
+        return lookupResult;
+    }
+
+    private LookupResult resolveContactsUri(String handle, final Uri personUri) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DBG) Slog.w(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        mPeopleCache.put(handle, lookupResult);
+        return lookupResult;
+    }
+
+    private final static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    // TODO: rework this function before shipping
+    private static int priorityBumpMap(int incomingScore) {
+        //assumption is that scale runs from [-2*pm, 2*pm]
+        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
+        int theScore = incomingScore;
+        // enforce input in range
+        theScore = clamp(theScore, -2 * pm, 2 * pm);
+        if (theScore != incomingScore) return incomingScore;
+        // map -20 -> -20 and -10 -> 5 (when pm = 10)
+        if (theScore <= -pm) {
+            theScore += 1.5 * (theScore + 2 * pm);
+        } else {
+            // map 0 -> 10, 10 -> 15, 20 -> 20;
+            theScore += 0.5 * (2 * pm - theScore);
+        }
+        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
+                + ", score after " + theScore + ".");
+        return theScore;
+    }
+
+    @Override
+    public void initialize(Context context) {
+        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mContext = context;
+        mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
+        mEnabled = ENABLE_PEOPLE_SCORER && 1 == Settings.Global.getInt(
+                mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_SCORER, 0);
+    }
+
+    @Override
+    public int getScore(Notification notification, int score) {
+        if (notification == null || !mEnabled) {
+            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
+            return score;
+        }
+        float contactScore = findMaxContactScore(notification.extras);
+        if (contactScore > 0f) {
+            if (DBG) Slog.v(TAG, "Notification references a real contact. Promoted!");
+            score = priorityBumpMap(score);
+        } else {
+            if (DBG) Slog.v(TAG, "Notification lacks any valid contact reference. Not promoted!");
+        }
+        return score;
+    }
+
+    private static class LookupResult {
+        private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000;  // 1hr
+        public static final int INVALID_ID = -1;
+
+        private final long mExpireMillis;
+        private int mId;
+
+        public LookupResult(int id) {
+            mId = id;
+            mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
+        }
+
+        public boolean isExpired() {
+            return mExpireMillis < System.currentTimeMillis();
+        }
+
+        public boolean isInvalid() {
+            return mId == INVALID_ID || isExpired();
+        }
+
+        public float getRank() {
+            if (isInvalid()) {
+                return 0f;
+            } else {
+                return 1f;  // TODO: finer grained score
+            }
+        }
+
+        public LookupResult setId(int id) {
+            mId = id;
+            return this;
+        }
+    }
+}
+
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 63ff5a0..b78c70f 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -25,12 +25,24 @@
 interface IKeyguardService {
     boolean isShowing();
     boolean isSecure();
-    boolean isShowingAndNotHidden();
+    boolean isShowingAndNotOccluded();
     boolean isInputRestricted();
     boolean isDismissable();
     oneway void verifyUnlock(IKeyguardExitCallback callback);
     oneway void keyguardDone(boolean authenticated, boolean wakeup);
-    oneway void setHidden(boolean isHidden);
+
+    /**
+     * Sets the Keyguard as occluded when a window dismisses the Keyguard with flag
+     * FLAG_SHOW_ON_LOCK_SCREEN.
+     *
+     * @param isOccluded Whether the Keyguard is occluded by another window.
+     * @return See IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_*. This is needed because
+     *         PhoneWindowManager needs to set these flags immediately and can't wait for the
+     *         Keyguard thread to pick it up. In the hidden case, PhoneWindowManager is solely
+     *         responsible to make sure that the flags are unset.
+     */
+    int setOccluded(boolean isOccluded);
+
     oneway void dismiss();
     oneway void onDreamingStarted();
     oneway void onDreamingStopped();
diff --git a/core/java/com/android/internal/policy/IKeyguardServiceConstants.java b/core/java/com/android/internal/policy/IKeyguardServiceConstants.java
new file mode 100644
index 0000000..b88174a
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardServiceConstants.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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;
+
+/**
+ * @hide
+ */
+public class IKeyguardServiceConstants {
+
+    /**
+     * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
+     * Don't change the keyguard window flags.
+     */
+    public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE = 0;
+
+    /**
+     * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
+     * Set the keyguard window flags to FLAG_SHOW_WALLPAPER and PRIVATE_FLAG_KEYGUARD.
+     */
+    public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS = 1;
+
+    /**
+     * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
+     * Unset the keyguard window flags to FLAG_SHOW_WALLPAPER and PRIVATE_FLAG_KEYGUARD.
+     */
+    public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS = 2;
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 02bd4ac..86c9fe3 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -57,10 +57,6 @@
     }
 
     @Override
-    public void dispatchScreenState(boolean on) {
-    }
-
-    @Override
     public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
     }
 
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
index 961e471..5f3c5f9 100644
--- a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
+++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
@@ -107,8 +107,6 @@
         }
         if (background instanceof ColorDrawable) {
             mModestyPanel.setBackgroundDrawable(background);
-        } else {
-            mModestyPanel.setBackgroundColor(Color.BLACK);
         }
         SizeAdaptiveLayout.LayoutParams layout =
                 new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 24e0b0a..7a4728d 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -49,6 +49,8 @@
     jfieldID    minDelay;
     jfieldID    fifoReservedEventCount;
     jfieldID    fifoMaxEventCount;
+    jfieldID    stringType;
+    jfieldID    requiredPermission;
 } gSensorOffsets;
 
 
@@ -73,6 +75,9 @@
     sensorOffsets.fifoReservedEventCount =
             _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
     sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
+    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
+    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
+                                                        "Ljava/lang/String;");
 }
 
 static jint
@@ -89,6 +94,8 @@
     const SensorOffsets& sensorOffsets(gSensorOffsets);
     jstring name = env->NewStringUTF(list->getName().string());
     jstring vendor = env->NewStringUTF(list->getVendor().string());
+    jstring stringType = env->NewStringUTF(list->getStringType().string());
+    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
@@ -100,7 +107,11 @@
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
                      list->getFifoReservedEventCount());
-    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
+    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+                     list->getFifoMaxEventCount());
+    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+                        requiredPermission);
     next++;
     return size_t(next) < count ? next : 0;
 }
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 6ae6c8f..d0269a3 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -146,8 +146,8 @@
         jlong renderNodePtr) {
     using namespace android::uirenderer;
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    TreeInfo info = {0};
-    renderNode->prepareTree(info);
+    TreeInfo ignoredInfo;
+    renderNode->prepareTree(ignoredInfo);
 }
 
 static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 2eb0d78..b2f17de 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -127,8 +127,8 @@
 static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    bool ignoredHasFunctors;
-    return layer->apply(&ignoredHasFunctors);
+    TreeInfo ignoredInfo;
+    return layer->apply(ignoredInfo);
 }
 
 static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 31a1de6..8dacfeb 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -376,7 +376,8 @@
 static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    return renderNode->stagingProperties().getMatrixFlags() == 0;
+    renderNode->mutateStagingProperties().updateMatrix();
+    return !renderNode->stagingProperties().hasTransformMatrix();
 }
 
 // ----------------------------------------------------------------------------
@@ -391,10 +392,7 @@
     renderNode->mutateStagingProperties().updateMatrix();
     const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix();
 
-    if (renderNode->stagingProperties().getMatrixFlags() == TRANSLATION) {
-        outMatrix->setTranslate(renderNode->stagingProperties().getTranslationX(),
-                renderNode->stagingProperties().getTranslationY());
-    } else if (transformMatrix) {
+    if (transformMatrix) {
         *outMatrix = *transformMatrix;
     } else {
         outMatrix->setIdentity();
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 159ffb2..8141a00 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -34,6 +34,7 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <ui/DisplayInfo.h>
+#include <ui/FrameStats.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -64,6 +65,16 @@
     delete ((ScreenshotClient*) context);
 }
 
+static struct {
+    nsecs_t UNDEFINED_TIME_NANO;
+    jmethodID init;
+} gWindowContentFrameStatsClassInfo;
+
+static struct {
+    nsecs_t UNDEFINED_TIME_NANO;
+    jmethodID init;
+} gWindowAnimationFrameStatsClassInfo;
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
@@ -371,6 +382,151 @@
     SurfaceComposerClient::unblankDisplay(token);
 }
 
+static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->clearLayerFrameStats();
+
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, just report we failed.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
+    jobject outStats) {
+    FrameStats stats;
+
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->getLayerFrameStats(&stats);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, fine just return empty stats.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
+    size_t frameCount = stats.desiredPresentTimesNano.size();
+
+    jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
+    if (postedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
+    if (presentedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
+    if (readyTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    nsecs_t postedTimesNanoSrc[frameCount];
+    nsecs_t presentedTimesNanoSrc[frameCount];
+    nsecs_t readyTimesNanoSrc[frameCount];
+
+    for (size_t i = 0; i < frameCount; i++) {
+        nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
+        if (postedTimeNano == INT64_MAX) {
+            postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        postedTimesNanoSrc[i] = postedTimeNano;
+
+        nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
+        if (presentedTimeNano == INT64_MAX) {
+            presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        presentedTimesNanoSrc[i] = presentedTimeNano;
+
+        nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
+        if (readyTimeNano == INT64_MAX) {
+            readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        readyTimesNanoSrc[i] = readyTimeNano;
+    }
+
+    env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
+    env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
+    env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
+
+    env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
+            postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
+
+    if (env->ExceptionCheck()) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
+    status_t err = SurfaceComposerClient::clearAnimationFrameStats();
+
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, just report we failed.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
+    FrameStats stats;
+
+    status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+
+    // The other end is not ready, fine just return empty stats.
+    if (err == NO_INIT) {
+        return JNI_FALSE;
+    }
+
+    jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
+    size_t frameCount = stats.desiredPresentTimesNano.size();
+
+    jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
+    if (presentedTimesNanoDst == NULL) {
+        return JNI_FALSE;
+    }
+
+    nsecs_t presentedTimesNanoSrc[frameCount];
+
+    for (size_t i = 0; i < frameCount; i++) {
+        nsecs_t presentedTimeNano = stats.desiredPresentTimesNano[i];
+        if (presentedTimeNano == INT64_MAX) {
+            presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
+        }
+        presentedTimesNanoSrc[i] = presentedTimeNano;
+    }
+
+    env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
+
+    env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
+            presentedTimesNanoDst);
+
+    if (env->ExceptionCheck()) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod sSurfaceControlMethods[] = {
@@ -426,6 +582,14 @@
             (void*)nativeBlankDisplay },
     {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
             (void*)nativeUnblankDisplay },
+    {"nativeClearContentFrameStats", "(J)Z",
+            (void*)nativeClearContentFrameStats },
+    {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
+            (void*)nativeGetContentFrameStats },
+    {"nativeClearAnimationFrameStats", "()Z",
+            (void*)nativeClearAnimationFrameStats },
+    {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
+            (void*)nativeGetAnimationFrameStats },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
@@ -441,6 +605,19 @@
     gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
     gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
     gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
+
+    jclass frameStatsClazz = env->FindClass("android/view/FrameStats");
+    jfieldID undefined_time_nano_field =  env->GetStaticFieldID(frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
+    nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
+
+    jclass contFrameStatsClazz = env->FindClass("android/view/WindowContentFrameStats");
+    gWindowContentFrameStatsClassInfo.init =  env->GetMethodID(contFrameStatsClazz, "init", "(J[J[J[J)V");
+    gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
+
+    jclass animFrameStatsClazz = env->FindClass("android/view/WindowAnimationFrameStats");
+    gWindowAnimationFrameStatsClassInfo.init =  env->GetMethodID(animFrameStatsClazz, "init", "(J[J)V");
+    gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
+
     return err;
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 36c8357..b5f489d 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -121,24 +121,10 @@
     proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
 }
 
-static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->destroyCanvas();
-}
-
-static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    proxy->attachFunctor(functor);
-}
-
-static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    proxy->detachFunctor(functor);
+    proxy->destroyCanvasAndSurface();
 }
 
 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
@@ -208,9 +194,7 @@
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList },
-    { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas },
-    { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor },
-    { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor },
+    { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
     { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0f772f1..b2709af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -483,6 +483,13 @@
         android:label="@string/permlab_writeProfile"
         android:description="@string/permdesc_writeProfile" />
 
+    <!-- Allows an application to access data from sensors that the user uses to
+         measure what is happening inside his/her body, such as heart rate. -->
+    <permission android:name="android.permission.BODY_SENSORS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:label="@string/permlab_bodySensors"
+        android:description="@string/permdesc_bodySensors" />
+
     <!-- =============================================================== -->
     <!-- Permissions for accessing the device calendar                   -->
     <!-- =============================================================== -->
@@ -1921,6 +1928,18 @@
         android:description="@string/permdesc_filter_events"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
+    <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
+        android:label="@string/permlab_retrieveWindowToken"
+        android:description="@string/permdesc_retrieveWindowToken"
+        android:protectionLevel="signature" />
+
+    <!-- @hide Allows an application to collect frame statistics -->
+    <permission android:name="android.permission.FRAME_STATS"
+         android:label="@string/permlab_frameStats"
+         android:description="@string/permdesc_frameStats"
+         android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to temporary enable accessibility on the device. -->
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
         android:label="@string/permlab_temporary_enable_accessibility"
diff --git a/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..32ddf7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..db9e172
--- /dev/null
+++ b/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..805cb29
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
new file mode 100644
index 0000000..c3791fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/notification_quantum_bg.xml b/core/res/res/drawable/notification_quantum_bg.xml
index 608115e..300a565 100644
--- a/core/res/res/drawable/notification_quantum_bg.xml
+++ b/core/res/res/drawable/notification_quantum_bg.xml
@@ -16,6 +16,16 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"  android:drawable="@drawable/notification_quantum_press" />
-    <item android:state_pressed="false" android:drawable="@drawable/notification_quantum_background" />
+    <item android:state_pressed="true">
+        <shape>
+            <solid android:color="#ffd0d0d0" />
+            <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+    <item>
+        <shape>
+            <solid android:color="#fffafafa" />
+            <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
 </selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/notification_quantum_background.xml b/core/res/res/drawable/notification_quantum_bg_dim.xml
similarity index 65%
rename from core/res/res/drawable/notification_quantum_background.xml
rename to core/res/res/drawable/notification_quantum_bg_dim.xml
index 7b508a9..ab0e049 100644
--- a/core/res/res/drawable/notification_quantum_background.xml
+++ b/core/res/res/drawable/notification_quantum_bg_dim.xml
@@ -15,7 +15,15 @@
   ~ limitations under the License
   -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#ffffffff" />
-    <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
-</shape>
\ No newline at end of file
+<touch-feedback
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:tint="#ffffffff"
+    android:tintMode="src_over"
+    >
+    <item>
+        <shape>
+            <solid android:color="#d4ffffff" />
+            <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+</touch-feedback>
\ No newline at end of file
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_quantum.xml
index e31c2c1..e34f64a 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_quantum.xml
@@ -15,12 +15,16 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true" android:state_pressed="true">
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <item android:state_pressed="true">
         <bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
             android:tint="?attr/colorControlActivated" />
     </item>
     <item>
         <bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+            android:tint="?attr/colorControlActivated" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
index 7b124ac..d172b05 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
@@ -15,12 +15,24 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-            android:tint="?attr/colorControlActivated" />
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
     </item>
     <item>
-        <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-            android:tint="?attr/colorControlNormal" />
+        <layer-list>
+            <item android:id="@id/background">
+                <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+                    android:tint="?attr/colorControlNormal" />
+            </item>
+            <item android:id="@id/secondaryProgress">
+                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+                    android:tint="?attr/colorControlNormal" />
+            </item>
+            <item android:id="@id/progress">
+                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </layer-list>
     </item>
 </selector>
diff --git a/core/res/res/layout/action_bar_home_quantum.xml b/core/res/res/layout/action_bar_home_quantum.xml
new file mode 100644
index 0000000..3968429
--- /dev/null
+++ b/core/res/res/layout/action_bar_home_quantum.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.internal.widget.ActionBarView$HomeView"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical|start">
+    <ImageView android:id="@android:id/up"
+        android:src="?android:attr/homeAsUpIndicator"
+        android:layout_gravity="center_vertical|start"
+        android:visibility="gone"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:scaleType="center" />
+    <ImageView android:id="@android:id/home"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:scaleType="fitCenter" />
+</view>
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml
index 8863cfa..8f3019d 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_quantum_base.xml
@@ -17,7 +17,6 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_quantum_bg"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="64dp"
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml
index 63935bb..45e69b1 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_quantum_big_base.xml
@@ -17,7 +17,6 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_quantum_bg"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_quantum_big_picture.xml b/core/res/res/layout/notification_template_quantum_big_picture.xml
index e49c3bd..f68e414 100644
--- a/core/res/res/layout/notification_template_quantum_big_picture.xml
+++ b/core/res/res/layout/notification_template_quantum_big_picture.xml
@@ -17,7 +17,6 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_quantum_bg"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml
index 516b0c4..f7769d7 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_quantum_big_text.xml
@@ -16,7 +16,6 @@
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_quantum_bg"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml
index c6192be..04974c4 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_quantum_inbox.xml
@@ -18,7 +18,6 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
-    android:background="@android:drawable/notification_quantum_bg"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     internal:layout_minHeight="65dp"
diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml
index c16a12c..3ad1f23 100644
--- a/core/res/res/layout/volume_adjust.xml
+++ b/core/res/res/layout/volume_adjust.xml
@@ -14,47 +14,38 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="480dp"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/visible_panel"
+    android:orientation="horizontal"
+    android:layout_width="300dp"
     android:layout_height="wrap_content">
+
     <LinearLayout
-        android:id="@+id/visible_panel"
-        android:layout_width="match_parent"
+        android:id="@+id/slider_group"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:background="@android:drawable/dialog_full_holo_dark"
-        android:orientation="horizontal"
-        >
-
-        <LinearLayout
-            android:id="@+id/slider_group"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:orientation="vertical"
-            >
-            <!-- Sliders go here -->
-        </LinearLayout>
-
-        <ImageView
-            android:id="@+id/expand_button_divider"
-            android:src="?attr/dividerVertical"
-            android:layout_width="wrap_content"
-            android:layout_height="32dip"
-            android:scaleType="fitXY"
-            android:layout_gravity="top"
-            android:layout_marginTop="16dip"
-            android:layout_marginBottom="16dip"
-            />
-
-        <ImageView
-            android:id="@+id/expand_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top"
-            android:padding="16dip"
-            android:background="?attr/selectableItemBackground"
-            android:src="@drawable/ic_sysbar_quicksettings"
-            />
-
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <!-- Sliders go here -->
     </LinearLayout>
-</FrameLayout>
\ No newline at end of file
+
+    <ImageView
+        android:id="@+id/expand_button_divider"
+        android:src="?attr/dividerVertical"
+        android:layout_width="wrap_content"
+        android:layout_height="32dip"
+        android:scaleType="fitXY"
+        android:layout_gravity="top"
+        android:layout_marginTop="16dip"
+        android:layout_marginBottom="16dip" />
+
+    <ImageView
+        android:id="@+id/expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top"
+        android:padding="16dip"
+        android:background="?attr/selectableItemBackground"
+        android:src="@drawable/ic_sysbar_quicksettings" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml
index 4a0fbaf..57cecf4 100644
--- a/core/res/res/layout/volume_adjust_item.xml
+++ b/core/res/res/layout/volume_adjust_item.xml
@@ -26,14 +26,14 @@
         android:id="@+id/stream_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="16dip"
+        android:paddingLeft="16dip"
         android:background="?attr/selectableItemBackground"
-        />
+        android:contentDescription="@null" />
 
     <SeekBar
         style="?android:attr/seekBarStyle"
         android:id="@+id/seekbar"
-        android:layout_width="300dp"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:padding="16dip"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 88f5c54..f9b00a9 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind aan \'n TV-invoer"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Laat die houer toe om aan die topvlak-koppelvlak van \'n TV-invoer te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"voeg \'n toesteladministrateur by of verwyder een"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Laat die houer aktiewe toesteladministrateurs byvoeg of verwyder. Behoort nooit nodig te wees vir normale programme nie."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"verander skermoriëntasie"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 101c4dc..c6ff2da 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"الالتزام بإدخال التلفزيون"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لإدخال التلفزيون. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"إضافة مشرف جهاز أو إزالته"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"للسماح بحامل البطاقة بإضافة مشرفي أجهزة نشطين أو إزالتهم. لا يلزم ذلك أبدًا للتطبيقات العادية."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1d063f6..618eba9 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"Vinculació a una entrada de televisor"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permet que el titular es vinculi a la interfície de nivell superior d\'una entrada de televisor. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"afegeix un administrador al dispositiu o suprimeix-lo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet que el titular afegeixi administradors actius al dispositiu o en suprimeixi. No s\'hauria de necessitar per a les aplicacions normals."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3c113f0..73913a2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"knyt til en tv-indgang"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for en tv-indgang. Dette bør ikke være nødvendigt i normale apps."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tilføje eller fjerne en enhedsadministrator"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillader, at man tilføjer eller fjerner aktive enhedsadministratorer. Dette burde aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index e1e9106..456b56d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"σύνδεση σε μία είσοδο τηλεόρασης"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανώτερου επιπέδου μιας εισόδου τηλεόρασης. Δεν απαιτείται ποτέ για τις συνηθισμένες εφαρμογές."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"προσθήκη ή κατάργηση ενός διαχειριστή συσκευής"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Επιτρέπει στον κάτοχο να προσθέτει ή να καταργεί ενεργούς διαχειριστές συσκευών. Δεν θα πρέπει να ζητείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8da35f1..528c840 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Allows the holder to bind to the top-level interface of a TV input. Should never be needed for normal apps."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 8da35f1..528c840 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Allows the holder to bind to the top-level interface of a TV input. Should never be needed for normal apps."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index adb033f..38774d7 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"sidumine TV-sisendiga"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lubab omanikul siduda TV-sisendi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"seadme administraatori lisamine või eemaldamine"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Võimaldab omanikul lisada või eemaldada aktiivseid seadme administraatoreid. Tavarakenduste puhul ei tohiks see kunagi vajalik olla."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuda ekraani paigutust"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1419bc4..4a1c409 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्‍यवस्‍थापक के साथ सहभागिता करें"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्‍यवस्‍थापक को उद्देश्य भेजने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"टीवी इनपुट से आबद्ध करें"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"धारक को किसी टीवी इनपुट के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"स्‍क्रीन अभिविन्‍यास बदलें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index dde0a5b..10e4ac8 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"povezivanje s TV ulazom"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Nositelju omogućuje vezanje uz sučelje najviše razine TV ulaza. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodavanje ili uklanjanje administratora uređaja"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Omogućuje nositelju dodavanje ili uklanjanje administratora aktivnih uređaja. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 41a1fb9..fd3a887 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"csatlakozás tévébemenethez"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy tévébemenet legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b1d94e6..eddb9c85 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"mengikat ke masukan TV"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Memungkinkan pemegang mengikat ke antarmuka tingkat tinggi dari masukan TV. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"menambah atau menghapus admin perangkat"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Memungkinkan pemegang menambahkan atau menghapus administrator perangkat aktif. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 222dfe3..43b94b7 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"‏מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"איגוד לקלט טלוויזיה"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"הרשאה זו מאפשרת למחזיק בה לבצע איגוד לממשק הרמה העליונה של קלט טלוויזיה. הרשאה זו אף פעם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"הוספה או הסרה של מנהלי מכשיר"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"מאפשרת לבעלים להוסיף או להסיר מנהלי מכשיר פעילים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 8dbd6ac..cb4f257 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទង​ជា​មួយ​អ្នកគ្រប់គ្រង​ឧបករណ៍"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យ​ម្ចាស់​ផ្ញើ​គោលបំណង​​ទៅ​អ្នក​គ្រប់គ្រង​ឧបករណ៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់​ទៅ​ការ​បញ្ចូល​ទូរទស្សន៍"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុចប្រទាក់​កម្រិត​ខ្ពស់​នៃ​ការ​បញ្ចូល​ទូរទស្សន៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាត​​​ឲ្យ​ម្ចាស់​​​បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​ឧបករណ៍​សកម្ម​ចេញ​។ មិន​គួរ​ប្រើ​សម្រាប់​កម្មវិធី​​ធម្មតា​ទេ​។"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរ​ទិស​អេក្រង់"</string>
diff --git a/core/res/res/values-land/dimens_quantum.xml b/core/res/res/values-land/dimens_quantum.xml
new file mode 100644
index 0000000..7789219
--- /dev/null
+++ b/core/res/res/values-land/dimens_quantum.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+
+    <!-- Default height of an action bar. -->
+    <dimen name="action_bar_default_height_quantum">48dp</dimen>
+    <!-- Default padding of an action bar. -->
+    <dimen name="action_bar_default_padding_quantum">0dp</dimen>
+
+</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 79b8a33..178176f 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"ຜູກ​ກັບ​ການ​ປ້ອນ​ຂໍ້​ມູນ​ເຂົ້າ​ໂທ​ລະ​ທັດ"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ຜູ່​ຖື​ຜູກ​ຕິດ​ກັບ​ສ່ວ​ນ​ຕິດ​ຕໍ່​ລະ​ດັບ​ສູງ​ສຸດ​ຂອງ​ການ​ປ້ອນ​ຂໍ້​ມູນ​ເຂົ້າ​ໂທ​ລະ​ທັດ. ແອັບຯ​ທົ່ວ​ໄປ​ບໍ່​ຄວນ​ຈຳ​ເປັນ​ຕ້ອງ​ໃຊ້."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ເພີ່ມ ຫຼືລຶບຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດລຶບ ຫຼືລຶບຂໍ້ມູນອຸປະກອນທີ່ນຳໃຊ້ໄດ້. ແອັບຯທົ່ວໄປບໍ່ຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ປ່ຽນລວງຂອງໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 99184d2..69d2420 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"susisaistyti su TV įvestimi"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Leidžiama savininkui susisaistyti su aukščiausio lygio TV įvesties sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridėti arba pašalinti įrenginio administratorių"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Savininkui leidžiama pridėti aktyvių įrenginio administratorių arba juos pašalinti. Neturėtų reikėti įprastoms programoms."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 433115c..965e3eb 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"Izveidot saiti ar TV ieeju"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Ļauj īpašniekam izveidot saiti ar TV ieejas augšējā līmeņa saskarni. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pievienot vai noņemt ierīces administratoru"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ļauj īpašniekam pievienot vai noņemt aktīvos ierīces administratorus. Nekad nav nepieciešama parastām lietotnēm."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 442b856..1284d92 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"ТВ оролт холбох"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Эзэмшигч нь ТВ оролтын дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"төхөөрөмжийн админ нэмэх, хасах"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Эзэмшигч нь идэвхтэй төхөөрөмжийн администраторыг нэмэх, хасах боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"дэлгэцний чиглэлийг солих"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 379e3dd..65595ab 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a uma entrada de TV"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite ao titular vincular à interface de nível superior de uma entrada de TV. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o titular adicione ou remova administradores de dispositivos ativos. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index aa467bb..851addc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"viazanie na televízny vstup"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania televízneho vstupu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridanie alebo odstránenie správcu zariadenia"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umožňuje držiteľovi pridať alebo odstrániť správcov aktívnych zariadení. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 0fed1e3..10d5376 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"повезивање са ТВ улазом"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Дозвољава власнику да се повеже са интерфејсом ТВ улаза највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавање или уклањање администратора уређаја"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозвољава власнику да додаје или уклања активне администраторе уређаја. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5afc0cd..820764c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"binda till en tv-insignal"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en tv-insignal. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lägga till eller ta bort en enhetsadministratör"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Innehavaren får lägga till eller ta bort aktiva enhetsadministratörer. Detta ska normalt inte behövas för vanliga appar."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e31392e..6758319 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"прив’язуватися до вводу телевізора"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня вводу телевізора. Ніколи не застосовується для звичайних додатків."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index fa499d9..45f1856 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"允許應用程式繫結至電視訊號輸入裝置的頂層介面,但一般應用程式並不需要使用。"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (不建議一般應用程式使用)。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕瀏覽方向"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1359dd9..ccaf14c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -384,10 +384,8 @@
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"bophezela kokokufaka kwe-TV"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Ivumela umbambi ukuthi abophezele uxhumano nomsebenzisi kwezinga eliphezulu lokokufaka kwe-TV. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fbe066a..d5e78a5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1370,7 +1370,7 @@
     </string-array>
 
     <string-array name="config_notificationScorers">
-        <item>com.android.internal.notification.DemoContactNotificationScorer</item>
+        <item>com.android.internal.notification.PeopleNotificationScorer</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 94123a2..6b2c788 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -201,7 +201,7 @@
     <dimen name="textview_error_popup_default_width">240dip</dimen>
 
     <!-- Volume panel y offset -->
-    <dimen name="volume_panel_top">80dp</dimen>
+    <dimen name="volume_panel_top">16dp</dimen>
 
     <!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
     <dimen name="default_app_widget_padding_left">8dp</dimen>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index 3913752..02e61e2 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -17,6 +17,8 @@
 
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height_quantum">56dp</dimen>
+    <!-- Default padding of an action bar. -->
+    <dimen name="action_bar_default_padding_quantum">4dp</dimen>
     <!-- Vertical padding around action bar icons. -->
     <dimen name="action_bar_icon_vertical_padding_quantum">16dp</dimen>
     <!-- Text size for action bar titles -->
@@ -28,6 +30,10 @@
     <!-- Bottom margin for action bar subtitles -->
     <dimen name="action_bar_subtitle_bottom_margin_quantum">5dp</dimen>
 
+    <dimen name="action_button_min_width_quantum">48dp</dimen>
+    <dimen name="action_button_min_height_quantum">48dp</dimen>
+    <dimen name="action_overflow_min_width_quantum">36dp</dimen>
+
     <dimen name="text_size_display_4_quantum">112sp</dimen>
     <dimen name="text_size_display_3_quantum">56sp</dimen>
     <dimen name="text_size_display_2_quantum">45sp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4a121d1..fde5e3f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -830,6 +830,20 @@
          user consent.</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_retrieveWindowToken">retrieve window token</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_retrieveWindowToken">Allows an application to retrieve
+        the window token. Malicious apps may perfrom unauthorized interaction with
+        the application window impersonating the system.</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_frameStats">retrieve frame statistics</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_frameStats">Allows an application to collect
+        frame statistics. Malicious apps may observe the frame statistics
+        of windows from other apps.</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_filter_events">filter events</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_filter_events">Allows an application to register an input filter
@@ -1329,6 +1343,14 @@
       as your name and contact information.  This means the app can identify you
       and may send your profile information to others.</string>
 
+    <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
+    <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+    </string>
+    <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_bodySensors" product="default">Allows the app to
+      access data from sensors you use to measure what’s happening inside your
+      body, such as heart rate.</string>
+
     <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
     <string name="permlab_readSocialStream" product="default">read your social stream</string>
     <string name="permdesc_readSocialStream" product="default">Allows the app
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 2720d61..595dc79 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -713,10 +713,9 @@
     <style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
 
     <style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
-        <item name="minWidth">@dimen/action_button_min_width</item>
+        <item name="minWidth">@dimen/action_button_min_width_quantum</item>
+        <item name="minHeight">@dimen/action_button_min_height_quantum</item>
         <item name="gravity">center</item>
-        <item name="paddingStart">12dip</item>
-        <item name="paddingEnd">12dip</item>
         <item name="scaleType">center</item>
         <item name="maxLines">2</item>
     </style>
@@ -729,6 +728,9 @@
         <item name="src">@drawable/ic_menu_moreoverflow_quantum</item>
         <item name="background">?attr/actionBarItemBackground</item>
         <item name="contentDescription">@string/action_menu_overflow_description</item>
+        <item name="minWidth">@dimen/action_overflow_min_width_quantum</item>
+        <item name="minHeight">@dimen/action_button_min_height_quantum</item>
+        <item name="scaleType">center</item>
     </style>
 
     <style name="Widget.Quantum.ActionButton.TextButton" parent="Widget.Quantum.ButtonBar"/>
@@ -756,16 +758,19 @@
     </style>
 
     <style name="Widget.Quantum.ActionBar" parent="Widget.ActionBar">
-        <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
-        <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
         <item name="background">@null</item>
         <item name="backgroundStacked">@null</item>
         <item name="backgroundSplit">@null</item>
+        <item name="displayOptions">showHome|showTitle</item>
         <item name="divider">?attr/dividerVertical</item>
+        <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
         <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
         <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
         <item name="progressBarPadding">32dip</item>
         <item name="itemPadding">8dip</item>
+        <item name="homeLayout">@layout/action_bar_home_quantum</item>
+        <item name="gravity">center_vertical</item>
     </style>
 
     <style name="Widget.Quantum.ActionBar.Solid">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac6c15d..f285bce 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1254,7 +1254,6 @@
   <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
   <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
   <java-symbol type="style" name="Theme.IconMenu" />
-  <java-symbol type="style" name="Theme.Panel.Volume" />
 
   <java-symbol type="attr" name="mediaRouteButtonStyle" />
   <java-symbol type="attr" name="externalRouteEnabledDrawable" />
@@ -1642,6 +1641,8 @@
   <java-symbol type="layout" name="notification_template_quantum_inbox" />
   <java-symbol type="color" name="notification_action_legacy_color_filter" />
   <java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
+  <java-symbol type="drawable" name="notification_quantum_bg_dim" />
+  <java-symbol type="drawable" name="notification_quantum_bg" />
 
     <!-- From SystemUI -->
   <java-symbol type="anim" name="push_down_in" />
@@ -1836,5 +1837,6 @@
   <java-symbol type="attr" name="subtitleTextAppearance" />
   <java-symbol type="drawable" name="ic_lock_bugreport" />
   <java-symbol type="id" name="icon_frame" />
+  <java-symbol type="style" name="Animation.VolumePanel" />
 
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6f9e55b..7b3d5e3 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -892,11 +892,6 @@
         <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
-    <style name="Theme.Panel.Volume">
-        <item name="android:windowAnimationStyle">@android:style/Animation.VolumePanel</item>
-        <item name="android:windowCloseOnTouchOutside">true</item>
-    </style>
-
     <!-- Default theme with an Action Bar. -->
     <style name="Theme.WithActionBar">
         <item name="android:windowActionBar">true</item>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 9e235d6..aef01ac 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -300,10 +300,10 @@
         <item name="actionModeStyle">@style/Widget.Quantum.ActionMode</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.Quantum.ActionButton.CloseMode</item>
         <item name="actionBarStyle">@style/Widget.Quantum.ActionBar.Solid</item>
-        <item name="actionBarSize">@dimen/action_bar_default_height</item>
+        <item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
         <item name="actionModePopupWindowStyle">@style/Widget.Quantum.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarTheme">@null</item>
+        <item name="actionBarTheme">@style/Theme.Quantum.ActionBar</item>
         <item name="actionBarItemBackground">@drawable/item_background_quantum</item>
 
         <item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
@@ -638,10 +638,10 @@
         <item name="actionModeStyle">@style/Widget.Quantum.Light.ActionMode</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.Quantum.Light.ActionButton.CloseMode</item>
         <item name="actionBarStyle">@style/Widget.Quantum.Light.ActionBar.Solid</item>
-        <item name="actionBarSize">@dimen/action_bar_default_height</item>
+        <item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
         <item name="actionModePopupWindowStyle">@style/Widget.Quantum.Light.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarTheme">@null</item>
+        <item name="actionBarTheme">@style/Theme.Quantum.Light.ActionBar</item>
         <item name="actionBarItemBackground">@drawable/item_background_quantum</item>
 
         <item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
@@ -708,12 +708,20 @@
         <item name="colorButtonPressedColored">?attr/colorPrimaryDark</item>
     </style>
 
+    <style name="Theme.Quantum.ActionBar">
+        <item name="colorControlActivated">?attr/colorControlNormal</item>
+    </style>
+
+    <style name="Theme.Quantum.Light.ActionBar">
+        <item name="colorControlActivated">?attr/colorControlNormal</item>
+    </style>
+
     <!-- Variant of the quantum (light) theme that has a solid (opaque) action bar
          with an inverse color profile. The dark action bar sharply stands out against
          the light content. -->
     <style name="Theme.Quantum.Light.DarkActionBar">
         <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarTheme">@style/Theme.Quantum</item>
+        <item name="actionBarTheme">@style/Theme.Quantum.ActionBar</item>
     </style>
 
     <!-- Variant of the quantum (dark) theme with no action bar. -->
diff --git a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
index efd06bf..18411b0 100644
--- a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
@@ -438,17 +438,6 @@
         assertEquals("ModestyPanel color should match the SizeAdaptiveLayout",
                      panelColor.getColor(), Color.RED);
     }
-
-    @SmallTest
-    public void testModestyPanelHasDefault() {
-        inflate(R.layout.size_adaptive);
-        View panel = mSizeAdaptiveLayout.getModestyPanel();
-        assertNull("SizeAdaptiveLayout should have no background for this test",
-                     mSizeAdaptiveLayout.getBackground());
-        assertTrue("ModestyPanel should have a ColorDrawable background",
-                   panel.getBackground() instanceof ColorDrawable);
-    }
-
     @SmallTest
     public void testOpenSmallEvenWhenLargeIsActuallySmall() {
         inflate(R.layout.size_adaptive_lies);
diff --git a/docs/html/images/tools/as-android.png b/docs/html/images/tools/as-android.png
new file mode 100644
index 0000000..7808ed1
--- /dev/null
+++ b/docs/html/images/tools/as-android.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointline.png b/docs/html/images/tools/as-breakpointline.png
new file mode 100644
index 0000000..9aea880
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointline.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointswindow.png b/docs/html/images/tools/as-breakpointswindow.png
new file mode 100644
index 0000000..a40b459
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointswindow.png
Binary files differ
diff --git a/docs/html/images/tools/as-capture.png b/docs/html/images/tools/as-capture.png
new file mode 100644
index 0000000..02f9f6f
--- /dev/null
+++ b/docs/html/images/tools/as-capture.png
Binary files differ
diff --git a/docs/html/images/tools/as-currentproc.png b/docs/html/images/tools/as-currentproc.png
new file mode 100644
index 0000000..4be8305
--- /dev/null
+++ b/docs/html/images/tools/as-currentproc.png
Binary files differ
diff --git a/docs/html/images/tools/as-ddmslog.png b/docs/html/images/tools/as-ddmslog.png
new file mode 100644
index 0000000..b53b8fe
--- /dev/null
+++ b/docs/html/images/tools/as-ddmslog.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugbutton.png b/docs/html/images/tools/as-debugbutton.png
new file mode 100644
index 0000000..55e95d1
--- /dev/null
+++ b/docs/html/images/tools/as-debugbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugdevices.png b/docs/html/images/tools/as-debugdevices.png
new file mode 100644
index 0000000..09a9d0e
--- /dev/null
+++ b/docs/html/images/tools/as-debugdevices.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugview.png b/docs/html/images/tools/as-debugview.png
new file mode 100644
index 0000000..0349147
--- /dev/null
+++ b/docs/html/images/tools/as-debugview.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugwindowbutton.png b/docs/html/images/tools/as-debugwindowbutton.png
new file mode 100644
index 0000000..9016778
--- /dev/null
+++ b/docs/html/images/tools/as-debugwindowbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-devicecapture.png b/docs/html/images/tools/as-devicecapture.png
new file mode 100644
index 0000000..3236a89
--- /dev/null
+++ b/docs/html/images/tools/as-devicecapture.png
Binary files differ
diff --git a/docs/html/images/tools/as-evalexpbutton.png b/docs/html/images/tools/as-evalexpbutton.png
new file mode 100644
index 0000000..85b3c74
--- /dev/null
+++ b/docs/html/images/tools/as-evalexpbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-launchavdm.png b/docs/html/images/tools/as-launchavdm.png
new file mode 100644
index 0000000..bf15981
--- /dev/null
+++ b/docs/html/images/tools/as-launchavdm.png
Binary files differ
diff --git a/docs/html/images/tools/as-monitorbutton.png b/docs/html/images/tools/as-monitorbutton.png
new file mode 100644
index 0000000..6bdc3a5
--- /dev/null
+++ b/docs/html/images/tools/as-monitorbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-record.png b/docs/html/images/tools/as-record.png
new file mode 100644
index 0000000..5f7fa99
--- /dev/null
+++ b/docs/html/images/tools/as-record.png
Binary files differ
diff --git a/docs/html/images/tools/as-restart.png b/docs/html/images/tools/as-restart.png
new file mode 100644
index 0000000..12d2923
--- /dev/null
+++ b/docs/html/images/tools/as-restart.png
Binary files differ
diff --git a/docs/html/images/tools/as-resumeprogrambutton.png b/docs/html/images/tools/as-resumeprogrambutton.png
new file mode 100644
index 0000000..8096937
--- /dev/null
+++ b/docs/html/images/tools/as-resumeprogrambutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-showdevview.png b/docs/html/images/tools/as-showdevview.png
new file mode 100644
index 0000000..602a6ad
--- /dev/null
+++ b/docs/html/images/tools/as-showdevview.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepintobutton.png b/docs/html/images/tools/as-stepintobutton.png
new file mode 100644
index 0000000..569d4ed
--- /dev/null
+++ b/docs/html/images/tools/as-stepintobutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoutbutton.png b/docs/html/images/tools/as-stepoutbutton.png
new file mode 100644
index 0000000..ef8871f
--- /dev/null
+++ b/docs/html/images/tools/as-stepoutbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoverbutton.png b/docs/html/images/tools/as-stepoverbutton.png
new file mode 100644
index 0000000..1c487df
--- /dev/null
+++ b/docs/html/images/tools/as-stepoverbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-variablesview.png b/docs/html/images/tools/as-variablesview.png
new file mode 100644
index 0000000..6a0b987
--- /dev/null
+++ b/docs/html/images/tools/as-variablesview.png
Binary files differ
diff --git a/docs/html/images/tools/as-varviewbutton.png b/docs/html/images/tools/as-varviewbutton.png
new file mode 100644
index 0000000..2ad4c58
--- /dev/null
+++ b/docs/html/images/tools/as-varviewbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-viewbreakbutton.png b/docs/html/images/tools/as-viewbreakbutton.png
new file mode 100644
index 0000000..22723d4
--- /dev/null
+++ b/docs/html/images/tools/as-viewbreakbutton.png
Binary files differ
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 9d5e8c1..6b63ba7 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -35,10 +35,10 @@
 
 </div>
 
-  
+
 
 <div id="mac" class="docs" style="display:none">
-  
+
 <h3>Getting started on Mac</h3>
 
 <ol>
@@ -62,7 +62,7 @@
 
 
 <div id="linux" class="docs" style="display:none">
-  
+
 <h3>Getting started on Linux</h3>
 
 <ol>
@@ -97,17 +97,23 @@
   <li>Here are the steps to install Java and Eclipse, prior to installing
   the Android SDK and ADT Plugin.
     <ol>
-      <li>If you are running a 64-bit distribution on your development
-      machine, you need to install the <code>ia32-libs</code> package using
-      <code>apt-get:</code>:
-      <pre>apt-get install ia32-libs</pre>
+      <li><p>If you are running a 64-bit distribution on your development
+      machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander)
+      and above, install the <code>libncurses5:i386</code>, <code>libstdc++6:i386</code>, and
+      <code>zlib1g:i386</code> packages using <code>apt-get</code>:</p>
+      <pre class="no-pretty-print">sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386</pre>
+      <p>For earlier versions of Ubuntu, install the <code>ia32-libs</code> package using
+      <code>apt-get</code>:</p>
+      <pre class="no-pretty-print">apt-get install ia32-libs</pre>
       </li>
-      <li>Next, install Java: <pre>apt-get install sun-java6-jdk</pre></li>
-      <li>The Ubuntu package manager does not currently offer an Eclipse 3.6
+      <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li>
+      <li>The Ubuntu package manager does not currently offer an Eclipse 3.7
       version for download, so we recommend that you download Eclipse from
       eclipse.org (<a
-      href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
-      downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+      href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>).
+      A Java or RCP version of Eclipse is recommended.</li>
       <li>Follow the steps given in previous sections to install the SDK
       and the ADT plugin. </li>
     </ol>
@@ -137,7 +143,7 @@
     // not running a compatible OS, so just show all the docs
     $('.docs').show();
   }
-  
+
   function showAll() {
     $('.docs').each(function() {
       if (!$(this).is(':visible')) {
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
new file mode 100644
index 0000000..7e2efe3
--- /dev/null
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -0,0 +1,346 @@
+page.title=Debugging with Android Studio
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#runDebug">Run your App in Debug Mode</a></li>
+  <li><a href="#systemLog">Use the System Log</a>
+    <ol>
+      <li><a href="#systemLogWrite">Write log messages in your code</a></li>
+      <li><a href="#systemLogView">View the system log</a></li>
+    </ol>
+  </li>
+  <li><a href="#breakPoints">Work with Breakpoints</a>
+    <ol>
+        <li><a href="#breakPointsView">View and configure breakpoints</a></li>
+        <li><a href="#breakPointsDebug">Debug your app with breakpoints</a></li>
+    </ol>
+  </li>
+  <li><a href="#deviceMonitor">Analyze Runtime Metrics to Optimize your App</a></li>
+  <li><a href="#screenCap">Capture Screenshots and Videos</a></li>
+</ol>
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
+<li><a href="{@docRoot}tools/help/monitor.html">Device Monitor</a></li>
+<li><a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a></li>
+</div>
+</div>
+
+<p>Android Studio enables you to debug apps running on the emulator or on an Android device.
+With Android Studio, you can:</p>
+
+<ul>
+    <li>Select a device to debug your app on.</li>
+    <li>View the system log.</li>
+    <li>Set breakpoints in your code.</li>
+    <li>Examine variables and evaluate expressions at run time.</li>
+    <li>Run the debugging tools from the Android SDK.</li>
+    <li>Capture screenshots and videos of your app.</li>
+</ul>
+
+<p>To debug your app, Android Studio builds a debuggable version of your app, connects
+to a device or to the emulator, installs the app and runs it. The IDE shows the system log
+while your app is running and provides debugging tools to filter log messages, work with
+breakpoints, and control the execution flow.</p>
+
+
+<h2 id="runDebug">Run your App in Debug Mode</h2>
+
+<div class="figure" style="width:419px">
+    <img src="{@docRoot}images/tools/as-debugdevices.png" alt=""/>
+    <p class="img-caption"><strong>Figure 1.</strong> The Choose Device window enables you to
+    select a physical Android device or a virtual device to debug your app.</p>
+</div>
+
+<p>To run your app in debug mode, you build an APK signed with a debug key and install it on a
+physical Android device or on the Android emulator.
+To set up an Android device for development, see <a href="{@docRoot}tools/device.html">Using
+Hardware Devices</a>. For more information about the emulator provided by the Android SDK, see
+<a href="{@docRoot}tools/devices/emulator.html">Using the Emulator.</a></p>
+
+<p>To debug your app in Android Studio:</p>
+
+<ol>
+    <li>Open your project in Android Studio.</li>
+    <li>Click <strong>Debug</strong> <img src="{@docRoot}images/tools/as-debugbutton.png"
+        style="vertical-align:bottom;margin:0;height:22px"  alt=""/> in the toolbar.</li>
+    <li>On the <em>Choose Device</em> window, select a hardware device from the list or
+        choose a virtual device.</li>
+    <li>Click <strong>OK</strong>. Your app starts on the selected device.</li>
+</ol>
+
+<p>Figure 1 shows the <em>Choose Device</em> window. The list shows all the Android devices
+connected to your computer. Select <strong>Launch Emulator</strong> to use an Android virtual device
+instead. Click the ellipsis <img src="{@docRoot}images/tools/as-launchavdm.png"
+style="vertical-align:bottom;margin:0;height:19px" alt=""/> to open the
+<a href="{@docRoot}tools/devices/managing-avds.html">Android Virtual Device Manager</a>.</p>
+
+<p>Android Studio opens the <em>Debug</em> tool window when you debug your app. To open the
+<em>Debug</em> window manually, click <strong>Debug</strong>
+<img src="{@docRoot}images/tools/as-debugwindowbutton.png"
+alt="" style="vertical-align:bottom;margin:0;height:20px"/>.
+This window shows threads and variables in the <em>Debugger</em> tab, the device status in the
+<em>Console</em> tab, and the system log in the <em>Logcat</em> tab. The <em>Debug</em> tool
+window also provides other debugging tools covered in the following sections.</p>
+
+<img src="{@docRoot}images/tools/as-debugview.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The Debug tool window in Android Studio showing
+the current thread and the object tree for a variable.</p>
+
+
+<h2 id="systemLog">Use the System Log</h2>
+
+<p>The system log shows system messages while you debug your app. These messages include
+information from apps running on the device. If you want to use the
+system log to debug your app, make sure your code writes log messages and prints the stack
+trace for exceptions while your app is in the development phase.</p>
+
+<h3 id="systemLogWrite">Write log messages in your code</h3>
+
+<p>To write log messages in your code, use the {@link android.util.Log} class. Log messages
+help you understand the execution flow by collecting the system debug output while you interact
+with your app. Log messages can tell you what part of your application failed. For more
+information about logging, see <a href="{@docRoot}tools/debugging/debugging-log.html">
+Reading and Writing Logs</a>.</p>
+
+<p>The following example shows how you might add log messages to determine if previous state
+information is available when your activity starts:</p>
+
+<pre>
+import android.util.Log;
+...
+public class MyActivity extends Activity {
+    private static final String TAG = MyActivity.class.getSimpleName();
+    ...
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            Log.d(TAG, "onCreate() Restoring previous state");
+            /* restore state */
+        } else {
+            Log.d(TAG, "onCreate() No saved state available");
+            /* initialize app */
+        }
+    }
+}
+</pre>
+
+<p>During development, your code can also catch exceptions and write the stack trace to the system
+log:</p>
+
+<pre>
+void someOtherMethod() {
+    try {
+        ...
+    } catch (SomeException e) {
+        Log.d(TAG, "someOtherMethod()", e);
+    }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Remove debug log messages and stack trace print calls from
+your code when you are ready to publish your app. You could do this by setting a <code>DEBUG</code>
+flag and placing debug log messages inside conditional statements.</p>
+
+
+<h3 id="systemLogView">View the system log</h3>
+
+<p>Both the <em>Android DDMS</em> (Dalvik Debug Monitor Server) and the <em>Debug</em> tool windows
+show the system log; however, the <em>Android DDMS</em> tool window lets you view only log messages
+for a particular process. To view the system log on the <em>Android DDMS</em> tool window:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>If the system log is empty in the <em>Logcat view</em>, click <strong>Restart</strong>
+        <img src="{@docRoot}images/tools/as-restart.png" alt=""
+        style="vertical-align:bottom;margin:0;height:22px"/>.</li>
+</ol>
+
+<img src="{@docRoot}images/tools/as-ddmslog.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> The system log in the Android DDMS tool
+window.</p>
+
+<p>The <em>Android DDMS</em> tool window gives you access to some DDMS features from Android Studio.
+For more information about DDMS, see <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.
+</p>
+
+<p>The system log shows messages from Android services and other Android apps. To filter the log
+messages to view only the ones you are interested in, use the tools in the <em>Android DDMS</em>
+window:</p>
+
+<ul>
+    <li>To show only log messages for a particular process, select the process in the
+        <em>Devices</em> view and then click <strong>Only Show Logcat from Selected
+        Process</strong> <img src="{@docRoot}images/tools/as-currentproc.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>. If the <em>Devices</em> view
+        is not available, click <strong>Restore Devices View</strong>
+        <img src="{@docRoot}images/tools/as-showdevview.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> on the right of the <em>Android
+        DDMS</em> tool window. This button is only visible when you hide the <em>Devices</em>
+        window.</li>
+    <li>To filter log messages by log level, select a level under <em>Log Level</em> on the top
+        of the <em>Android DDMS</em> window.</li>
+    <li>To show only log messages that contain a particular string, enter the string in the search
+        box and press <strong>Enter</strong>.</li>
+</ul>
+
+
+<h2 id="breakPoints">Work with Breakpoints</h2>
+
+<p>Breakpoints enable you to pause the execution of your app at a particular line of code, examine
+variables, evaluate expressions, and continue the execution line by line. Use breakpoints to
+determine the causes of run-time errors that you can't fix by looking at your code only. To debug
+your app using breakpoints:</p>
+
+<ol>
+    <li>Open the source file in which you want to set a breakpoint.</li>
+    <li>Locate the line where you want to set a breakpoint and click on it.</li>
+    <li>Click on the yellow portion of the side bar to the left of this line, as shown in figure 5.</li>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+</ol>
+
+<p>Android Studio pauses the execution of your app when it reaches the breakpoint. You can then
+use the tools in the <em>Debug</em> tool window to identify the cause of the error.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointline.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> A red dot appears next to the line when you set
+a breakpoint.</p>
+
+<h3 id="breakPointsView">View and configure breakpoints</h3>
+
+<p>To view all the breakpoints and configure breakpoint settings, click <strong>View
+Breakpoints</strong> <img src="{@docRoot}images/tools/as-viewbreakbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the left side of the <em>Debug</em> tool
+window. The <em>Breakpoints</em> window appears, as shown in figure 6.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointswindow.png" alt="" />
+<p class="img-caption"><strong>Figure 6.</strong> The Breakpoints window lists all the current
+breakpoints and includes behavior settings for each.</p>
+
+<p>The <em>Breakpoints</em> window lets you enable or disable each breakpoint from the
+list on the left. If a breakpoint is disabled, Android Studio does not pause your app when
+it hits that breakpoint. Select a breakpoint from the list to configure its settings.
+You can configure a breakpoint to be disabled at first and have the system enable it after a
+different breakpoint is hit. You can also configure whether a breakpoint should be disabled after
+it is hit. To set a breakpoint for any exception, select <strong>Exception Breakpoints</strong>
+in the list of breakpoints.</p>
+
+<h3 id="breakPointsDebug">Debug your app with breakpoints</h3>
+
+<p>After you set breakpoints in your code, click <strong>Rerun</strong>
+<img src="{@docRoot}images/tools/as-restart.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> to start the app again. When a breakpoint is
+hit, Android Studio pauses the app and highlights the breakpoint in the source code. The
+<em>Debug</em> tool window lets you examine variables and control the execution step by
+step:</p>
+
+<ul>
+    <li>
+        <p>To examine the object tree for a variable, expand it in the <em>Variables</em> view. If
+        the <em>Variables</em> view is not visible, click <strong>Restore Variables View</strong>
+        <img src="{@docRoot}images/tools/as-varviewbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To evaluate an expression at the current execution point, click <strong>Evaluate
+        Expression</strong> <img src="{@docRoot}images/tools/as-evalexpbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the next line in the code (without entering a method), click <strong>Step
+        Over</strong> <img src="{@docRoot}images/tools/as-stepoverbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the first line inside a method call, click <strong>Step
+        Into</strong> <img src="{@docRoot}images/tools/as-stepintobutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the next line outside the current method, click <strong>Step
+        Out</strong> <img src="{@docRoot}images/tools/as-stepoutbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To continue running the app normally, click <strong>Resume Program</strong>
+        <img src="{@docRoot}images/tools/as-resumeprogrambutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+</ul>
+
+<img src="{@docRoot}images/tools/as-variablesview.png" alt="" />
+<p class="img-caption"><strong>Figure 7.</strong> The Variables view in the Debug tool window.</p>
+
+
+<h2 id="deviceMonitor">Analyze Runtime Metrics to Optimize your App</h2>
+
+<p>Even if your application does not generate runtime errors, this does not mean it is free of
+problems. You should also consider the following issues:</p>
+
+<ul>
+    <li>Does your app use memory efficiently?</li>
+    <li>Does your app generate unnecessary network traffic?</li>
+    <li>What methods should you focus your attention on to improve the performance of your app?</li>
+    <li>Does your app behave properly when the user receives a phone call or a message?</li>
+</ul>
+
+<p>The Android Device Monitor is a stand-alone tool with a graphical user interface for serveral
+Android application debugging and analysis tools, including the Dalvik Debug Monitor Server (DDMS).
+You can use the Android Device Monitor to analyze memory usage, profile methods,
+monitor network traffic and simulate incoming calls and messages.</p>
+
+<p>To open the Android Device Monitor from Android Studio, click
+<strong>Monitor</strong> <img src="{@docRoot}images/tools/as-monitorbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the toolbar. The Android Device Monitor
+opens in a new window.</p>
+
+<p>For more information about the Android Device Monitor and DDMS, see
+<a href="{@docRoot}tools/help/monitor.html">Device Monitor</a> and
+<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
+
+
+<h2 id="screenCap">Capture Screenshots and Videos</h2>
+
+<p>Android Studio enables you to capture a screenshot or a short video of the device screen
+while your app is running. Screenshots and videos are useful as promotional materials for your
+app, and you can also attach them to bug reports that you send to your development team.</p>
+
+<p>To take a screenshot of your app:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>Click <strong>Screen Capture</strong> <img src="{@docRoot}images/tools/as-capture.png"
+        style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+        <em>Android DDMS</em> tool window.</li>
+    <li>Optional: To add a device frame around your screenshot, enable the <em>Frame screenshot</em>
+        option.</li>
+    <li>Click <strong>Save</strong>.</li>
+</ol>
+
+<p>To take a video recording of your app:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>Click <strong>Screen Record</strong> <img src="{@docRoot}images/tools/as-record.png"
+        style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+        <em>Android DDMS</em> tool window.</li>
+    <li>Click <strong>Start Recording</strong>.</li>
+    <li>Interact with your app.</li>
+    <li>Click <strong>Stop Recording</strong>.</li>
+    <li>Enter a file name for the recording and click <strong>OK</strong>.</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index c281644..b29b87c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -38,6 +38,8 @@
               Using the Layout Editor</a></li>
           <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
               Building Your Project with Gradle</a></li>
+          <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+              Debugging with Android Studio</a></li>
           </ul>
       </li>
       <li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 2810c43..3773a49 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -44,9 +44,6 @@
  * Documentation pending.
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
-    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
-    private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
-
     /** The maximum number of ripples supported. */
     private static final int MAX_RIPPLES = 10;
 
@@ -153,10 +150,8 @@
      * @param tintMode A Porter-Duff blending mode
      */
     public void setTintMode(Mode tintMode) {
-        if (mState.mTintMode != tintMode) {
-            mState.mTintMode = tintMode;
-            invalidateSelf();
-        }
+        mState.setTintMode(tintMode);
+        invalidateSelf();
     }
 
     @Override
@@ -187,8 +182,8 @@
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
@@ -238,8 +233,8 @@
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
@@ -382,8 +377,9 @@
         // If we have ripples and content, we need a masking layer. This will
         // merge DST_ATOP onto (effectively under) the ripple layer.
         if (drewRipples && !projected && rippleRestoreCount >= 0) {
+            final PorterDuffXfermode xfermode = mState.getTintXfermode();
             canvas.saveLayer(bounds.left, bounds.top,
-                    bounds.right, bounds.bottom, getMaskingPaint(DST_ATOP), 0);
+                    bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
         }
 
         Drawable mask = null;
@@ -401,7 +397,7 @@
         if (mask != null && drewRipples) {
             // TODO: This will also mask the lower layer, which is bad.
             canvas.saveLayer(bounds.left, bounds.top, bounds.right,
-                    bounds.bottom, getMaskingPaint(DST_IN), 0);
+                    bounds.bottom, getMaskingPaint(mState.mTintXfermode), 0);
             mask.draw(canvas);
         }
 
@@ -459,7 +455,7 @@
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
         ColorStateList mTint;
-        Mode mTintMode;
+        PorterDuffXfermode mTintXfermode;
         boolean mPinned;
 
         public TouchFeedbackState(
@@ -469,10 +465,19 @@
             if (orig != null) {
                 mTouchThemeAttrs = orig.mTouchThemeAttrs;
                 mTint = orig.mTint;
-                mTintMode = orig.mTintMode;
+                mTintXfermode = orig.mTintXfermode;
                 mPinned = orig.mPinned;
             }
         }
+        
+        public void setTintMode(Mode mode) {
+            final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
+            mTintXfermode = new PorterDuffXfermode(invertedMode);
+        }
+        
+        public PorterDuffXfermode getTintXfermode() {
+            return mTintXfermode;
+        }
 
         @Override
         public boolean canApplyTheme() {
@@ -493,6 +498,33 @@
         public Drawable newDrawable(Resources res, Theme theme) {
             return new TouchFeedbackDrawable(this, res, theme);
         }
+
+        /**
+         * Inverts SRC and DST in PorterDuff blending modes.
+         */
+        private static Mode invertPorterDuffMode(Mode src) {
+            switch (src) {
+                case SRC_ATOP:
+                    return Mode.DST_ATOP;
+                case SRC_IN:
+                    return Mode.DST_IN;
+                case SRC_OUT:
+                    return Mode.DST_OUT;
+                case SRC_OVER:
+                    return Mode.DST_OVER;
+                case DST_ATOP:
+                    return Mode.SRC_ATOP;
+                case DST_IN:
+                    return Mode.SRC_IN;
+                case DST_OUT:
+                    return Mode.SRC_OUT;
+                case DST_OVER:
+                    return Mode.SRC_OVER;
+                default:
+                    // Everything else is agnostic to SRC versus DST.
+                    return src;
+            }
+        }
     }
 
     private TouchFeedbackDrawable(TouchFeedbackState state, Resources res, Theme theme) {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 6c0b722..493e276 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,8 +17,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
@@ -47,6 +47,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+
 /**
  * This lets you create a drawable based on an XML vector graphic
  * It can be defined in an XML file with the <code>&lt;vector></code> element.
@@ -172,7 +173,8 @@
     private static final int DEFAULT_DURATION = 1000;
     private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
 
-    private VectorDrawableState mVectorState;
+    private final VectorDrawableState mVectorState;
+
     private int mAlpha = 0xFF;
 
     public VectorDrawable() {
@@ -282,14 +284,17 @@
 
     @Override
     protected boolean onStateChange(int[] state) {
+        super.onStateChange(state);
+
         mVectorState.mVAnimatedPath.setState(state);
-        int direction = mVectorState.mVAnimatedPath.getTrigger(state);
-        if (direction>0) {
+
+        final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
+        if (direction > 0) {
             animateForward();
-        } else if (direction<0) {
+        } else if (direction < 0) {
             animateBackward();
         }
-        super.onStateChange(state);
+
         invalidateSelf();
         return true;
     }
@@ -310,7 +315,11 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mVectorState.mVAnimatedPath.draw(canvas);
+        final int saveCount = canvas.save();
+        final Rect bounds = getBounds();
+        canvas.translate(bounds.left, bounds.top);
+        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
+        canvas.restoreToCount(saveCount);
     }
 
     @Override
@@ -327,10 +336,6 @@
         // TODO: support color filter
     }
 
-    /**
-     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
-     * value of TRANSLUCENT.
-     */
     @Override
     public int getOpacity() {
         return PixelFormat.TRANSLUCENT;
@@ -364,38 +369,14 @@
         invalidateSelf();
     }
 
-    /**
-     * Sets the intrinsic (default) width for this shape.
-     *
-     * @param width the intrinsic width (in pixels)
-     */
-    public void setIntrinsicWidth(int width) {
-        if (mVectorState.mIntrinsicWidth != width) {
-            mVectorState.mIntrinsicWidth = width;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * Sets the intrinsic (default) height for this shape.
-     *
-     * @param height the intrinsic height (in pixels)
-     */
-    public void setIntrinsicHeight(int height) {
-        if (mVectorState.mIntrinsicHeight != height) {
-            mVectorState.mIntrinsicHeight = height;
-            invalidateSelf();
-        }
-    }
-
     @Override
     public int getIntrinsicWidth() {
-        return mVectorState.mIntrinsicWidth;
+        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mVectorState.mIntrinsicHeight;
+        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
     }
 
     @Override
@@ -408,25 +389,6 @@
         }
     }
 
-    /** @hide */
-    public static VectorDrawable create(Resources resources, int rid) {
-        try {
-            VectorDrawable drawable = new VectorDrawable();
-            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
-            factory.setNamespaceAware(true);
-            XmlPullParser xpp = resources.getXml(rid);
-            AttributeSet attrs = Xml.asAttributeSet(xpp);
-            drawable.inflate(resources, xpp, attrs);
-            drawable.setAnimationFraction(0);
-            return drawable;
-        } catch (XmlPullParserException e) {
-            Log.e(LOGTAG, "parser error", e);
-        } catch (IOException e) {
-            Log.e(LOGTAG, "parser error", e);
-        }
-        return null;
-    }
-
     @Override
     public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
@@ -450,6 +412,27 @@
         }
     }
 
+    /** @hide */
+    public static VectorDrawable create(Resources resources, int rid) {
+        try {
+            final XmlPullParser xpp = resources.getXml(rid);
+            final AttributeSet attrs = Xml.asAttributeSet(xpp);
+            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+            factory.setNamespaceAware(true);
+
+            final VectorDrawable drawable = new VectorDrawable();
+            drawable.inflate(resources, xpp, attrs);
+            drawable.setAnimationFraction(0);
+
+            return drawable;
+        } catch (XmlPullParserException e) {
+            Log.e(LOGTAG, "parser error", e);
+        } catch (IOException e) {
+            Log.e(LOGTAG, "parser error", e);
+        }
+        return null;
+    }
+
     private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final VAnimatedPath animatedPath = new VAnimatedPath();
@@ -543,9 +526,6 @@
     private void setAnimatedPath(VAnimatedPath animatedPath) {
         mVectorState.mVAnimatedPath = animatedPath;
 
-        setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth);
-        setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight);
-
         long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
         if (duration == -1) { // if it set to infinite set to 1 hour
             duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite
@@ -575,18 +555,12 @@
         ValueAnimator mBasicAnimator;
         VAnimatedPath mVAnimatedPath;
         Rect mPadding;
-        int mIntrinsicHeight;
-        int mIntrinsicWidth;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
                 mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
                 mPadding = new Rect(copy.mPadding);
-                mIntrinsicHeight = copy.mIntrinsicHeight;
-                mIntrinsicWidth = copy.mIntrinsicWidth;
-            } else {
-                mVAnimatedPath = new VAnimatedPath();
             }
         }
 
@@ -612,17 +586,31 @@
     }
 
     private static class VAnimatedPath {
-        private ArrayList<VAnimation> mCurrentAnimList = null;
+        private static final int [] TRIGGER_MAP = {
+                0,
+                R.attr.state_pressed,
+                R.attr.state_focused,
+                R.attr.state_hovered,
+                R.attr.state_selected,
+                R.attr.state_checkable,
+                R.attr.state_checked,
+                R.attr.state_activated,
+                R.attr.state_focused
+        };
+
+        private final Path mPath = new Path();
+        private final Path mRenderPath = new Path();
+        private final Matrix mMatrix = new Matrix();
+
+        private ArrayList<VAnimation> mCurrentAnimList;
         private VPath[] mCurrentPaths;
-        private float mAnimationValue = 0; // value goes from 0 to 1
-        private Paint mStrokePaint = null;
-        private Paint mFillPaint = null;
+        private Paint mStrokePaint;
+        private Paint mFillPaint;
         private PathMeasure mPathMeasure;
-        private Path mPath = new Path();
-        private Path mRenderPath = new Path();
-        private Matrix mMatrix = new Matrix();
-        private long mTotalDuration;
+
         private int[] mCurrentState = new int[0];
+        private float mAnimationValue;
+        private long mTotalDuration;
         private int mTrigger;
         private boolean mTriggerState;
 
@@ -634,11 +622,9 @@
         float mViewportHeight;
 
         public VAnimatedPath() {
-            setup();
         }
 
         public VAnimatedPath(VAnimatedPath copy) {
-            setup();
             mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
             mGroupList.addAll(copy.mGroupList);
             if (copy.mCurrentPaths != null) {
@@ -703,28 +689,7 @@
         }
 
         public void setTrigger(int trigger){
-            final int [] lut = {
-                    0,
-                    R.attr.state_pressed,
-                    R.attr.state_focused,
-                    R.attr.state_hovered,
-                    R.attr.state_selected,
-                    R.attr.state_checkable,
-                    R.attr.state_checked,
-                    R.attr.state_activated,
-                    R.attr.state_focused
-            };
-
-            mTrigger = lut[trigger];
-         }
-
-        private void setup(){
-            mStrokePaint = new Paint();
-            mStrokePaint.setStyle(Paint.Style.STROKE);
-            mStrokePaint.setAntiAlias(true);
-            mFillPaint = new Paint();
-            mFillPaint.setStyle(Paint.Style.FILL);
-            mFillPaint.setAntiAlias(true);
+            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
         }
 
         public long getTotalAnimationDuration() {
@@ -780,16 +745,12 @@
             }
         }
 
-        public void draw(Canvas canvas) {
+        public void draw(Canvas canvas, int w, int h) {
             if (mCurrentPaths == null) {
                 Log.e(LOGTAG,"mCurrentPaths == null");
                 return;
             }
 
-            // TODO: This should probably use getBounds().
-            final int w = canvas.getWidth();
-            final int h = canvas.getHeight();
-
             for (int i = 0; i < mCurrentPaths.length; i++) {
                 if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
                     drawPath(mCurrentPaths[i], canvas, w, h);
@@ -801,7 +762,7 @@
             final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
 
             vPath.toPath(mPath);
-            Path path = mPath;
+            final Path path = mPath;
 
             if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
                 float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
@@ -839,24 +800,36 @@
             }
 
             if (vPath.mFillColor != 0) {
+                if (mFillPaint == null) {
+                    mFillPaint = new Paint();
+                    mFillPaint.setStyle(Paint.Style.FILL);
+                    mFillPaint.setAntiAlias(true);
+                }
+
                 mFillPaint.setColor(vPath.mFillColor);
-                int alpha = 0xFF & (vPath.mFillColor >> 24);
-                mFillPaint.setAlpha(alpha);
                 canvas.drawPath(mRenderPath, mFillPaint);
             }
 
             if (vPath.mStrokeColor != 0) {
+                if (mStrokePaint == null) {
+                    mStrokePaint = new Paint();
+                    mStrokePaint.setStyle(Paint.Style.STROKE);
+                    mStrokePaint.setAntiAlias(true);
+                }
+
+                final Paint strokePaint = mStrokePaint;
                 if (vPath.mStrokeLineJoin != null) {
-                    mStrokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
                 }
+
                 if (vPath.mStrokeLineCap != null) {
-                    mStrokePaint.setStrokeCap(vPath.mStrokeLineCap);
+                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
                 }
-                mStrokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
-                mStrokePaint.setColor(vPath.mStrokeColor);
-                mStrokePaint.setAlpha(0xFF & (vPath.mStrokeColor >> 24));
-                mStrokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
-                canvas.drawPath(mRenderPath, mStrokePaint);
+
+                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
+                strokePaint.setColor(vPath.mStrokeColor);
+                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
+                canvas.drawPath(mRenderPath, strokePaint);
             }
         }
 
@@ -926,7 +899,7 @@
 
         private void parseViewport(Resources r, AttributeSet attrs)
                 throws XmlPullParserException {
-            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
+            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
             mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
             mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
             if (mViewportWidth == 0 || mViewportHeight == 0) {
@@ -938,7 +911,7 @@
 
         private void parseSize(Resources r, AttributeSet attrs)
                 throws XmlPullParserException  {
-            TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
+            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
             mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
             mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
             if (mBaseWidth == 0 || mBaseHeight == 0) {
@@ -947,6 +920,10 @@
             }
             a.recycle();
         }
+
+        private static final int getStateForTrigger(int trigger) {
+            return TRIGGER_MAP[trigger];
+        }
     }
 
     private static class VAnimation {
@@ -1324,8 +1301,8 @@
 
         boolean mAnimated = false;
         boolean mClip = false;
-        Paint.Cap mStrokeLineCap = null;
-        Paint.Join mStrokeLineJoin = null;
+        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
+        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
         float mStrokeMiterlimit = 4;
 
         private VNode[] mNode = null;
@@ -1775,32 +1752,29 @@
             return returnPath;
         }
 
-        private static int rgbInterpolate(float t, int color1, int color2) {
-            int ret;
-            if (color1 == color2) {
-                return color2;
-            }
-            if (color1 == 0) {
-                return color2;
-            }
-            if (color2 == 0) {
-                return color1;
+        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
+            if (startColor == endColor) {
+                return startColor;
+            } else if (startColor == 0) {
+                return endColor;
+            } else if (endColor == 0) {
+                return startColor;
             }
 
-            float t1 = 1 - t;
-            ret = 0xFF & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)));
-            color1 >>= 8;
-                    color2 >>= 8;
+            final int startA = (startColor >> 24) & 0xff;
+            final int startR = (startColor >> 16) & 0xff;
+            final int startG = (startColor >> 8) & 0xff;
+            final int startB = startColor & 0xff;
 
-                    ret |= 0xFF00 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 8);
-                    color1 >>= 8;
-                    color2 >>= 8;
-            ret |= 0xFF0000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 16);
-            color1 >>= 8;
-            color2 >>= 8;
-            ret |= 0xFF000000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 24);
+            final int endA = (endColor >> 24) & 0xff;
+            final int endR = (endColor >> 16) & 0xff;
+            final int endG = (endColor >> 8) & 0xff;
+            final int endB = endColor & 0xff;
 
-            return ret;
+            return ((startA + (int)(fraction * (endA - startA))) << 24) |
+                    ((startR + (int)(fraction * (endR - startR))) << 16) |
+                    ((startG + (int)(fraction * (endG - startG))) << 8) |
+                    ((startB + (int)(fraction * (endB - startB))));
         }
 
         public boolean isVisible(int[] state) {
@@ -1852,27 +1826,25 @@
             }
         }
 
-        private void nodeListToPath(VNode[] node, Path path) {
-            float[] current = new float[4];
-            for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, node[i].mType, node[i].mParams);
-            }
-        }
-
         public static void createPath(VNode[] node, Path path) {
             float[] current = new float[4];
+            char previousCommand = 'm';
             for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, node[i].mType, node[i].mParams);
+                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
+                previousCommand = node[i].mType;
             }
         }
 
-        private static void addCommand(Path path, float[] current, char cmd, float[] val) {
+        private static void addCommand(Path path, float[] current,
+                char previousCmd, char cmd, float[] val) {
 
             int incr = 2;
             float currentX = current[0];
             float currentY = current[1];
             float ctrlPointX = current[2];
             float ctrlPointY = current[3];
+            float reflectiveCtrlPointX;
+            float reflectiveCtrlPointY;
 
             switch (cmd) {
                 case 'z':
@@ -1952,12 +1924,8 @@
                         currentY = val[k + 0];
                         break;
                     case 'c': // curveto - Draws a cubic Bézier curve (relative)
-                        path.rCubicTo(val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3],
-                                val[k + 4],
-                                val[k + 5]);
+                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
 
                         ctrlPointX = currentX + val[k + 2];
                         ctrlPointY = currentY + val[k + 3];
@@ -1966,20 +1934,22 @@
 
                         break;
                     case 'C': // curveto - Draws a cubic Bézier curve
-                        path.cubicTo(val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3],
-                                val[k + 4],
-                                val[k + 5]);
+                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
                         currentX = val[k + 4];
                         currentY = val[k + 5];
                         ctrlPointX = val[k + 2];
                         ctrlPointY = val[k + 3];
-
                         break;
                     case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
-                        path.rCubicTo(currentX - ctrlPointX, currentY  - ctrlPointY,
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1],
                                 val[k + 2], val[k + 3]);
 
@@ -1989,47 +1959,63 @@
                         currentY += val[k + 3];
                         break;
                     case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
-                        path.cubicTo(2 * currentX - ctrlPointX,
-                                2 * currentY - ctrlPointY,
-                                val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3]);
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
                         ctrlPointX = val[k + 0];
                         ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
                     case 'q': // Draws a quadratic Bézier (relative)
                         path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
                         currentX += val[k + 2];
                         currentY += val[k + 3];
-                        ctrlPointX = val[k + 0];
-                        ctrlPointY = val[k + 1];
                         break;
                     case 'Q': // Draws a quadratic Bézier
                         path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
                         ctrlPointX = val[k + 0];
                         ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
                     case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
-                        path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY,
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1]);
-                        ctrlPointX = ctrlPointX + currentX;
-                        ctrlPointY = ctrlPointY + currentY;
+                        ctrlPointX = currentX + reflectiveCtrlPointX;
+                        ctrlPointY = currentY + reflectiveCtrlPointY;
                         currentX += val[k + 0];
                         currentY += val[k + 1];
-
                         break;
                     case 'T': // Draws a quadratic Bézier curve (reflective control point)
-                        path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY,
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
                                 val[k + 0], val[k + 1]);
+                        ctrlPointX = reflectiveCtrlPointX;
+                        ctrlPointY = reflectiveCtrlPointY;
                         currentX = val[k + 0];
-                        currentY = val[k + 1]; // TODO: Check this logic
-                        ctrlPointX = -(val[k + 0] - currentX);
-                        ctrlPointY = -(val[k + 1] - currentY);
+                        currentY = val[k + 1];
                         break;
                     case 'a': // Draws an elliptical arc
                         // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
@@ -2047,7 +2033,6 @@
                         currentY += val[k + 6];
                         ctrlPointX = currentX;
                         ctrlPointY = currentY;
-
                         break;
                     case 'A': // Draws an elliptical arc
                         drawArc(path,
@@ -2066,6 +2051,7 @@
                         ctrlPointY = currentY;
                         break;
                 }
+                previousCmd = cmd;
             }
             current[0] = currentX;
             current[1] = currentY;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index c64c169..285c8c3 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -41,6 +41,7 @@
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
+    setTransform(0);
     if (mLayer) {
         mCaches.resourceCache.decrementRefcount(mLayer);
     }
@@ -62,7 +63,7 @@
     }
 }
 
-bool DeferredLayerUpdater::apply(bool* hasFunctors) {
+bool DeferredLayerUpdater::apply(TreeInfo& info) {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
@@ -73,11 +74,7 @@
             success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
         }
         mLayer->setBlend(mBlend);
-        TreeInfo info = {0};
         mDisplayList->prepareTree(info);
-        if (info.hasFunctors) {
-            *hasFunctors = true;
-        }
         mLayer->updateDeferred(mDisplayList.get(),
                 mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
         mDirtyRect.setEmpty();
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 2cc9229..cc62caa 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,7 +77,7 @@
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply(bool* hasFunctors);
+    ANDROID_API bool apply(TreeInfo& info);
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 06f675e..f19da9d 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -286,12 +286,6 @@
 
     int getFlags() const { return mFlags; }
 private:
-    SaveOp() {}
-    DisplayListOp* reinit(int flags) {
-        mFlags = flags;
-        return this;
-    }
-
     int mFlags;
 };
 
@@ -318,12 +312,6 @@
     virtual const char* name() { return "RestoreToCount"; }
 
 private:
-    RestoreToCountOp() {}
-    DisplayListOp* reinit(int count) {
-        mCount = count;
-        return this;
-    }
-
     int mCount;
 };
 
@@ -514,7 +502,6 @@
     }
 
 protected:
-    ClipOp() {}
     virtual bool isRect() { return false; }
 
     SkRegion::Op mOp;
@@ -539,13 +526,6 @@
     virtual bool isRect() { return true; }
 
 private:
-    ClipRectOp() {}
-    DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
-        mOp = op;
-        mArea.set(left, top, right, bottom);
-        return this;
-    }
-
     Rect mArea;
 };
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 140a07a..6c73d68 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -258,11 +258,11 @@
 
 status_t DisplayListRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
-    int count = (meshWidth + 1) * (meshHeight + 1) * 2;
+    int vertexCount = (meshWidth + 1) * (meshHeight + 1);
     bitmap = refBitmap(bitmap);
-    vertices = refBuffer<float>(vertices, count);
+    vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex
     paint = refPaint(paint);
-    colors = refBuffer<int>(colors, count);
+    colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
 
     addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
                     vertices, colors, paint));
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 823ae7b..cf21834 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -50,17 +50,13 @@
 }
 
 RenderNode::RenderNode()
-        : mDestroyed(false)
-        , mNeedsPropertiesSync(false)
+        : mNeedsPropertiesSync(false)
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0) {
 }
 
 RenderNode::~RenderNode() {
-    LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
-
-    mDestroyed = true;
     delete mDisplayListData;
     delete mStagingDisplayListData;
 }
@@ -113,7 +109,7 @@
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
         // that are no longer used
-        TreeInfo oldTreeInfo = {0};
+        TreeInfo oldTreeInfo;
         prepareSubTree(oldTreeInfo, mDisplayListData);
         // TODO: The damage for the old tree should be accounted for
         delete mDisplayListData;
@@ -124,8 +120,15 @@
 
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
-        if (!info.hasFunctors) {
-            info.hasFunctors = subtree->functorCount;
+        TextureCache& cache = Caches::getInstance().textureCache;
+        info.hasFunctors |= subtree->functorCount;
+        // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
+        // and thus falling out of async drawing path.
+        if (subtree->ownedBitmapResources.size()) {
+            info.prepareTextures = false;
+        }
+        for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
+            info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
         }
         for (size_t i = 0; i < subtree->children().size(); i++) {
             RenderNode* childNode = subtree->children()[i]->mDisplayList;
@@ -154,8 +157,8 @@
     } else if (properties().getAnimationMatrix()) {
         renderer.concatMatrix(properties().getAnimationMatrix());
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             renderer.translate(properties().getTranslationX(), properties().getTranslationY());
         } else {
             renderer.concatMatrix(*properties().getTransformMatrix());
@@ -214,8 +217,8 @@
         mat4 anim(*properties().getAnimationMatrix());
         matrix.multiply(anim);
     }
-    if (properties().getMatrixFlags() != 0) {
-        if (properties().getMatrixFlags() == TRANSLATION) {
+    if (properties().hasTransformMatrix()) {
+        if (properties().isTransformTranslateOnly()) {
             matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
                     true3dTransform ? properties().getTranslationZ() : 0.0f);
         } else {
@@ -525,10 +528,6 @@
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
     const int level = handler.level();
-    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
-        ALOGW("Error: %s is drawing after destruction", mName.string());
-        CRASH();
-    }
     if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
         return;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 7853701..6688952 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -66,7 +66,13 @@
 class DrawDisplayListOp;
 
 struct TreeInfo {
+    TreeInfo()
+            : hasFunctors(false)
+            , prepareTextures(false)
+    {}
+
     bool hasFunctors;
+    bool prepareTextures;
     // TODO: Damage calculations? Flag to skip staging pushes for RT animations?
 };
 
@@ -210,7 +216,6 @@
     void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
 
     String8 mName;
-    bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
 
     bool mNeedsPropertiesSync;
     RenderProperties mProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index e7e7768..08829ef 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -27,6 +27,16 @@
 
 #include "Matrix.h"
 
+/**
+ * Convenience value to check for float values that are close enough to zero to be considered
+ * zero.
+ */
+#define NONZERO_EPSILON .001f
+
+static inline bool is_zero(float value) {
+    return (value >= -NONZERO_EPSILON) || (value <= NONZERO_EPSILON);
+}
+
 namespace android {
 namespace uirenderer {
 
@@ -42,22 +52,18 @@
         , mPivotX(0), mPivotY(0)
         , mLeft(0), mTop(0), mRight(0), mBottom(0)
         , mWidth(0), mHeight(0)
-        , mPrevWidth(-1), mPrevHeight(-1)
         , mPivotExplicitlySet(false)
-        , mMatrixDirty(false)
-        , mMatrixFlags(0)
+        , mMatrixOrPivotDirty(false)
         , mCaching(false) {
 }
 
 RenderProperties::ComputedFields::ComputedFields()
         : mTransformMatrix(NULL)
-        , mTransformMatrix3D(NULL)
         , mClipPath(NULL) {
 }
 
 RenderProperties::ComputedFields::~ComputedFields() {
     delete mTransformMatrix;
-    delete mTransformMatrix3D;
     delete mClipPath;
 }
 
@@ -82,7 +88,7 @@
         updateClipPath();
 
         // Force recalculation of the matrix, since other's dirty bit may be clear
-        mPrimitiveFields.mMatrixDirty = true;
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         updateMatrix();
     }
     return *this;
@@ -100,8 +106,8 @@
         ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
                 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
     }
-    if (mPrimitiveFields.mMatrixFlags != 0) {
-        if (mPrimitiveFields.mMatrixFlags == TRANSLATION) {
+    if (hasTransformMatrix()) {
+        if (isTransformTranslateOnly()) {
             ALOGD("%*sTranslate %.2f, %.2f, %.2f",
                     level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
         } else {
@@ -134,52 +140,36 @@
 }
 
 void RenderProperties::updateMatrix() {
-    if (mPrimitiveFields.mMatrixDirty) {
-        // NOTE: mComputedFields.mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
-        // to a pure translate. This is safe because the mPrimitiveFields.matrix isn't read in pure translate cases.
-        if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
-            if (!mComputedFields.mTransformMatrix) {
-                // only allocate a mPrimitiveFields.matrix if we have a complex transform
-                mComputedFields.mTransformMatrix = new SkMatrix();
-            }
-            if (!mPrimitiveFields.mPivotExplicitlySet) {
-                if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
-                    mPrimitiveFields.mPrevWidth = mPrimitiveFields.mWidth;
-                    mPrimitiveFields.mPrevHeight = mPrimitiveFields.mHeight;
-                    mPrimitiveFields.mPivotX = mPrimitiveFields.mPrevWidth / 2.0f;
-                    mPrimitiveFields.mPivotY = mPrimitiveFields.mPrevHeight / 2.0f;
-                }
-            }
-
-            if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
-                mComputedFields.mTransformMatrix->setTranslate(
-                        mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-            } else {
-                if (!mComputedFields.mTransformMatrix3D) {
-                    mComputedFields.mTransformMatrix3D = new SkMatrix();
-                }
-                mComputedFields.mTransformMatrix->reset();
-                mComputedFields.mTransformCamera.save();
-                mComputedFields.mTransformMatrix->preScale(
-                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
-                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
-                mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
-                mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
-                mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
-                mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
-                        mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
-                mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
-                mComputedFields.mTransformCamera.restore();
-            }
+    if (mPrimitiveFields.mMatrixOrPivotDirty) {
+        if (!mComputedFields.mTransformMatrix) {
+            // only allocate a mPrimitiveFields.matrix if we have a complex transform
+            mComputedFields.mTransformMatrix = new SkMatrix();
         }
-        mPrimitiveFields.mMatrixDirty = false;
+        if (!mPrimitiveFields.mPivotExplicitlySet) {
+            mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
+            mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
+        }
+        SkMatrix* transform = mComputedFields.mTransformMatrix;
+        transform->reset();
+        if (is_zero(getRotationX()) && is_zero(getRotationY())) {
+            transform->setTranslate(getTranslationX(), getTranslationY());
+            transform->preRotate(getRotation(), getPivotX(), getPivotY());
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+        } else {
+            SkMatrix transform3D;
+            mComputedFields.mTransformCamera.save();
+            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+            mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
+            mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
+            mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
+            mComputedFields.mTransformCamera.getMatrix(&transform3D);
+            transform3D.preTranslate(-getPivotX(), -getPivotY());
+            transform3D.postTranslate(getPivotX() + getTranslationX(),
+                    getPivotY() + getTranslationY());
+            transform->postConcat(transform3D);
+            mComputedFields.mTransformCamera.restore();
+        }
+        mPrimitiveFields.mMatrixOrPivotDirty = false;
     }
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index dd68210..4270da2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,12 +28,6 @@
 #include "RevealClip.h"
 #include "Outline.h"
 
-#define TRANSLATION 0x0001
-#define ROTATION    0x0002
-#define ROTATION_3D 0x0004
-#define SCALE       0x0008
-#define PIVOT       0x0010
-
 class SkBitmap;
 class SkPaint;
 
@@ -114,7 +108,7 @@
     void setTranslationX(float translationX) {
         if (translationX != mPrimitiveFields.mTranslationX) {
             mPrimitiveFields.mTranslationX = translationX;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -125,7 +119,7 @@
     void setTranslationY(float translationY) {
         if (translationY != mPrimitiveFields.mTranslationY) {
             mPrimitiveFields.mTranslationY = translationY;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -136,7 +130,7 @@
     void setTranslationZ(float translationZ) {
         if (translationZ != mPrimitiveFields.mTranslationZ) {
             mPrimitiveFields.mTranslationZ = translationZ;
-            onTranslationUpdate();
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -147,12 +141,7 @@
     void setRotation(float rotation) {
         if (rotation != mPrimitiveFields.mRotation) {
             mPrimitiveFields.mRotation = rotation;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotation == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -163,12 +152,7 @@
     void setRotationX(float rotationX) {
         if (rotationX != mPrimitiveFields.mRotationX) {
             mPrimitiveFields.mRotationX = rotationX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -179,12 +163,7 @@
     void setRotationY(float rotationY) {
         if (rotationY != mPrimitiveFields.mRotationY) {
             mPrimitiveFields.mRotationY = rotationY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mRotationX == 0.0f && mPrimitiveFields.mRotationY == 0.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~ROTATION_3D;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= ROTATION_3D;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -195,12 +174,7 @@
     void setScaleX(float scaleX) {
         if (scaleX != mPrimitiveFields.mScaleX) {
             mPrimitiveFields.mScaleX = scaleX;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -211,12 +185,7 @@
     void setScaleY(float scaleY) {
         if (scaleY != mPrimitiveFields.mScaleY) {
             mPrimitiveFields.mScaleY = scaleY;
-            mPrimitiveFields.mMatrixDirty = true;
-            if (mPrimitiveFields.mScaleX == 1.0f && mPrimitiveFields.mScaleY == 1.0f) {
-                mPrimitiveFields.mMatrixFlags &= ~SCALE;
-            } else {
-                mPrimitiveFields.mMatrixFlags |= SCALE;
-            }
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
         }
     }
 
@@ -226,12 +195,7 @@
 
     void setPivotX(float pivotX) {
         mPrimitiveFields.mPivotX = pivotX;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -245,12 +209,7 @@
 
     void setPivotY(float pivotY) {
         mPrimitiveFields.mPivotY = pivotY;
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mPivotX == 0.0f && mPrimitiveFields.mPivotY == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~PIVOT;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= PIVOT;
-        }
+        mPrimitiveFields.mMatrixOrPivotDirty = true;
         mPrimitiveFields.mPivotExplicitlySet = true;
     }
 
@@ -264,7 +223,7 @@
 
     void setCameraDistance(float distance) {
         if (distance != getCameraDistance()) {
-            mPrimitiveFields.mMatrixDirty = true;
+            mPrimitiveFields.mMatrixOrPivotDirty = true;
             mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
         }
     }
@@ -278,8 +237,8 @@
         if (left != mPrimitiveFields.mLeft) {
             mPrimitiveFields.mLeft = left;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -292,8 +251,8 @@
         if (top != mPrimitiveFields.mTop) {
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -306,8 +265,8 @@
         if (right != mPrimitiveFields.mRight) {
             mPrimitiveFields.mRight = right;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -320,8 +279,8 @@
         if (bottom != mPrimitiveFields.mBottom) {
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -336,8 +295,8 @@
             mPrimitiveFields.mTop = top;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -350,8 +309,8 @@
             mPrimitiveFields.mBottom = bottom;
             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -360,8 +319,8 @@
         if (offset != 0) {
             mPrimitiveFields.mLeft += offset;
             mPrimitiveFields.mRight += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -370,8 +329,8 @@
         if (offset != 0) {
             mPrimitiveFields.mTop += offset;
             mPrimitiveFields.mBottom += offset;
-            if (mPrimitiveFields.mMatrixFlags > TRANSLATION && !mPrimitiveFields.mPivotExplicitlySet) {
-                mPrimitiveFields.mMatrixDirty = true;
+            if (!mPrimitiveFields.mPivotExplicitlySet) {
+                mPrimitiveFields.mMatrixOrPivotDirty = true;
             }
         }
     }
@@ -392,11 +351,17 @@
         return mAnimationMatrix;
     }
 
-    uint32_t getMatrixFlags() const {
-        return mPrimitiveFields.mMatrixFlags;
+    bool hasTransformMatrix() const {
+        return getTransformMatrix() && !getTransformMatrix()->isIdentity();
+    }
+
+    // May only call this if hasTransformMatrix() is true
+    bool isTransformTranslateOnly() const {
+        return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
     }
 
     const SkMatrix* getTransformMatrix() const {
+        LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
         return mComputedFields.mTransformMatrix;
     }
 
@@ -452,14 +417,6 @@
     }
 
 private:
-    void onTranslationUpdate() {
-        mPrimitiveFields.mMatrixDirty = true;
-        if (mPrimitiveFields.mTranslationX == 0.0f && mPrimitiveFields.mTranslationY == 0.0f && mPrimitiveFields.mTranslationZ == 0.0f) {
-            mPrimitiveFields.mMatrixFlags &= ~TRANSLATION;
-        } else {
-            mPrimitiveFields.mMatrixFlags |= TRANSLATION;
-        }
-    }
 
     // Rendering properties
     struct PrimitiveFields {
@@ -478,10 +435,8 @@
         float mPivotX, mPivotY;
         int mLeft, mTop, mRight, mBottom;
         int mWidth, mHeight;
-        int mPrevWidth, mPrevHeight;
         bool mPivotExplicitlySet;
-        bool mMatrixDirty;
-        uint32_t mMatrixFlags;
+        bool mMatrixOrPivotDirty;
         bool mCaching;
     } mPrimitiveFields;
 
@@ -506,7 +461,6 @@
         SkMatrix* mTransformMatrix;
 
         Sk3DView mTransformCamera;
-        SkMatrix* mTransformMatrix3D;
         SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
         SkRegion::Op mClipPathOp;
     } mComputedFields;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 7923ce7..e783905 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -25,14 +25,14 @@
 namespace uirenderer {
 
 Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
         mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
         mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
         mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
 }
 
 Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
         mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
         mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
         mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index d48ec59..d5601f8 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -94,6 +94,12 @@
      */
     const UvMapper* uvMapper;
 
+    /**
+     * Whether or not the Texture is marked in use and thus not evictable for
+     * the current frame. This is reset at the start of a new frame.
+     */
+    bool isInUse;
+
 private:
     /**
      * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 01d72d1..34e2265 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -121,29 +121,49 @@
 // Caching
 ///////////////////////////////////////////////////////////////////////////////
 
-Texture* TextureCache::get(const SkBitmap* bitmap) {
+void TextureCache::resetMarkInUse() {
+    LruCache<const SkBitmap*, Texture*>::Iterator iter(mCache);
+    while (iter.next()) {
+        iter.value()->isInUse = false;
+    }
+}
+
+bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
+    if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
+        ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
+                bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+        return false;
+    }
+    return true;
+}
+
+// Returns a prepared Texture* that either is already in the cache or can fit
+// in the cache (and is thus added to the cache)
+Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
     Texture* texture = mCache.get(bitmap);
 
     if (!texture) {
-        if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
-            ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
-                    bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+        if (!canMakeTextureFromBitmap(bitmap)) {
             return NULL;
         }
 
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
+        bool canCache = size < mMaxSize;
         // Don't even try to cache a bitmap that's bigger than the cache
-        if (size < mMaxSize) {
-            while (mSize + size > mMaxSize) {
+        while (canCache && mSize + size > mMaxSize) {
+            Texture* oldest = mCache.peekOldestValue();
+            if (oldest && !oldest->isInUse) {
                 mCache.removeOldest();
+            } else {
+                canCache = false;
             }
         }
 
-        texture = new Texture();
-        texture->bitmapSize = size;
-        generateTexture(bitmap, texture, false);
+        if (canCache) {
+            texture = new Texture();
+            texture->bitmapSize = size;
+            generateTexture(bitmap, texture, false);
 
-        if (size < mMaxSize) {
             mSize += size;
             TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
                      bitmap, texture->id, size, mSize);
@@ -151,16 +171,42 @@
                 ALOGD("Texture created, size = %d", size);
             }
             mCache.put(bitmap, texture);
-        } else {
-            texture->cleanup = true;
         }
-    } else if (bitmap->getGenerationID() != texture->generation) {
+    } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
+        // Texture was in the cache but is dirty, re-upload
+        // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
         generateTexture(bitmap, texture, true);
     }
 
     return texture;
 }
 
+bool TextureCache::prefetchAndMarkInUse(const SkBitmap* bitmap) {
+    Texture* texture = getCachedTexture(bitmap);
+    if (texture) {
+        texture->isInUse = true;
+    }
+    return texture;
+}
+
+Texture* TextureCache::get(const SkBitmap* bitmap) {
+    Texture* texture = getCachedTexture(bitmap);
+
+    if (!texture) {
+        if (!canMakeTextureFromBitmap(bitmap)) {
+            return NULL;
+        }
+
+        const uint32_t size = bitmap->rowBytes() * bitmap->height();
+        texture = new Texture();
+        texture->bitmapSize = size;
+        generateTexture(bitmap, texture, false);
+        texture->cleanup = true;
+    }
+
+    return texture;
+}
+
 Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
     Texture* texture = new Texture();
     texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index e33c60d..48a10c2 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -62,6 +62,18 @@
     void operator()(const SkBitmap*& bitmap, Texture*& texture);
 
     /**
+     * Resets all Textures to not be marked as in use
+     */
+    void resetMarkInUse();
+
+    /**
+     * Attempts to precache the SkBitmap. Returns true if a Texture was successfully
+     * acquired for the bitmap, false otherwise. If a Texture was acquired it is
+     * marked as in use.
+     */
+    bool prefetchAndMarkInUse(const SkBitmap* bitmap);
+
+    /**
      * Returns the texture associated with the specified bitmap. If the texture
      * cannot be found in the cache, a new texture is generated.
      */
@@ -116,6 +128,11 @@
     void setFlushRate(float flushRate);
 
 private:
+
+    bool canMakeTextureFromBitmap(const SkBitmap* bitmap);
+
+    Texture* getCachedTexture(const SkBitmap* bitmap);
+
     /**
      * Generates the texture from a bitmap into the specified texture structure.
      *
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c5122e2..16baf77 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -313,18 +313,15 @@
         , mDirtyRegionsEnabled(false)
         , mOpaque(!translucent)
         , mCanvas(0)
-        , mHaveNewSurface(false)
-        , mInvokeFunctorsPending(false)
-        , mInvokeFunctorsTask(this) {
+        , mHaveNewSurface(false) {
     mGlobalContext = GlobalContext::get();
 }
 
 CanvasContext::~CanvasContext() {
-    removeFunctorsTask();
-    destroyCanvas();
+    destroyCanvasAndSurface();
 }
 
-void CanvasContext::destroyCanvas() {
+void CanvasContext::destroyCanvasAndSurface() {
     if (mCanvas) {
         delete mCanvas;
         mCanvas = 0;
@@ -385,12 +382,18 @@
     mCanvas->setViewport(width, height);
 }
 
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
-        bool* hasFunctors) {
+void CanvasContext::makeCurrent() {
     mGlobalContext->makeCurrent(mEglSurface);
+}
+
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+        TreeInfo& info) {
+    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
+    makeCurrent();
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
         DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
-        LOG_ALWAYS_FATAL_IF(!update->apply(hasFunctors), "Failed to update layer!");
+        bool success = update->apply(info);
+        LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
         if (update->backingLayer()->deferredUpdateScheduled) {
             mCanvas->pushLayerUpdate(update->backingLayer());
         }
@@ -431,61 +434,23 @@
     }
 }
 
-void InvokeFunctorsTask::run() {
-    mContext->invokeFunctors();
-}
-
-void CanvasContext::attachFunctor(Functor* functor) {
-    if (!mCanvas) return;
-
-    mCanvas->attachFunctor(functor);
-    removeFunctorsTask();
-    queueFunctorsTask(0);
-}
-
-void CanvasContext::detachFunctor(Functor* functor) {
-    if (!mCanvas) return;
-
-    mCanvas->detachFunctor(functor);
-}
-
 void CanvasContext::invokeFunctor(Functor* functor) {
+    ATRACE_CALL();
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
     if (mGlobalContext->hasContext()) {
         requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
-    (*functor)(mode, NULL);
-}
-
-void CanvasContext::invokeFunctors() {
-    mInvokeFunctorsPending = false;
-
-    if (!mCanvas) return;
-
-    requireSurface();
-    Rect dirty;
-    mCanvas->invokeFunctors(dirty);
-}
-
-void CanvasContext::removeFunctorsTask() {
-    if (!mInvokeFunctorsPending) return;
-
-    mInvokeFunctorsPending = false;
-    mRenderThread.remove(&mInvokeFunctorsTask);
-}
-
-void CanvasContext::queueFunctorsTask(int delayMs) {
-    if (mInvokeFunctorsPending) return;
-
-    mInvokeFunctorsPending = true;
-    mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
+    // TODO: Remove the dummy info in the future
+    DrawGlInfo dummyInfo;
+    memset(&dummyInfo, 0, sizeof(DrawGlInfo));
+    (*functor)(mode, &dummyInfo);
 }
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    bool hasFunctors;
-    layer->apply(&hasFunctors);
+    TreeInfo info;
+    layer->apply(info);
     return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a24162e..a3fe591 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -23,6 +23,7 @@
 #include <utils/Functor.h>
 #include <utils/Vector.h>
 
+#include "../RenderNode.h"
 #include "RenderTask.h"
 
 #define FUNCTOR_PROCESS_DELAY 4
@@ -31,8 +32,6 @@
 namespace uirenderer {
 
 class DeferredLayerUpdater;
-class RenderNode;
-class DisplayListData;
 class OpenGLRenderer;
 class Rect;
 class Layer;
@@ -43,17 +42,6 @@
 class CanvasContext;
 class RenderThread;
 
-class InvokeFunctorsTask : public RenderTask {
-public:
-    InvokeFunctorsTask(CanvasContext* context)
-        : mContext(context) {}
-
-    virtual void run();
-
-private:
-    CanvasContext* mContext;
-};
-
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 class CanvasContext {
@@ -65,14 +53,13 @@
     void updateSurface(EGLNativeWindowType window);
     void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, bool* hasFunctors);
+    void makeCurrent();
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void drawDisplayList(RenderNode* displayList, Rect* dirty);
-    void destroyCanvas();
+    void destroyCanvasAndSurface();
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
-    void attachFunctor(Functor* functor);
-    void detachFunctor(Functor* functor);
     void invokeFunctor(Functor* functor);
 
     void runWithGlContext(RenderTask* task);
@@ -85,11 +72,6 @@
     void swapBuffers();
     void requireSurface();
 
-    friend class InvokeFunctorsTask;
-    void invokeFunctors();
-    void removeFunctorsTask();
-    void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
-
     void requireGlContext();
 
     GlobalContext* mGlobalContext;
@@ -100,10 +82,6 @@
     bool mOpaque;
     OpenGLRenderer* mCanvas;
     bool mHaveNewSurface;
-
-    bool mInvokeFunctorsPending;
-    InvokeFunctorsTask mInvokeFunctorsTask;
-
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 372d0d0..f542d43 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,7 +30,7 @@
 namespace uirenderer {
 namespace renderthread {
 
-DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
+DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
@@ -69,23 +69,14 @@
     LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!");
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
-    postAndWait(renderThread, MODE_FULL);
+    postAndWait(renderThread);
 
     // Reset the single-frame data
     mDirty.setEmpty();
     mRenderNode = 0;
 }
 
-void DrawFrameTask::flushStateChanges(RenderThread* renderThread) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
-
-    postAndWait(renderThread, MODE_STATE_ONLY);
-}
-
-void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) {
-    LOG_ALWAYS_FATAL_IF(mode == MODE_INVALID, "That's not a real mode, silly!");
-
-    mTaskMode = mode;
+void DrawFrameTask::postAndWait(RenderThread* renderThread) {
     AutoMutex _lock(mLock);
     renderThread->queue(this);
     mSignal.wait(mLock);
@@ -94,14 +85,8 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
     bool canUnblockUiThread = syncFrameState();
 
-    if (mTaskMode == MODE_STATE_ONLY) {
-        unblockUiThread();
-        return;
-    }
-
     // Grab a copy of everything we need
     Rect dirtyCopy(mDirty);
     sp<RenderNode> renderNode = mRenderNode;
@@ -119,20 +104,20 @@
     }
 }
 
+static void prepareTreeInfo(TreeInfo& info) {
+    info.prepareTextures = true;
+}
+
 bool DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
-
-    bool hasFunctors = false;
-    mContext->processLayerUpdates(&mLayers, &hasFunctors);
-
-    // If we don't have an mRenderNode this is a state flush only
-    if (mRenderNode.get()) {
-        TreeInfo info = {0};
-        mRenderNode->prepareTree(info);
-        hasFunctors |= info.hasFunctors;
-    }
-
-    return !hasFunctors;
+    mContext->makeCurrent();
+    Caches::getInstance().textureCache.resetMarkInUse();
+    TreeInfo info;
+    prepareTreeInfo(info);
+    mContext->processLayerUpdates(&mLayers, info);
+    mRenderNode->prepareTree(info);
+    // If prepareTextures is false, we ran out of texture cache space
+    return !info.hasFunctors && info.prepareTextures;
 }
 
 void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index a512408..055d4cf 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -56,18 +56,11 @@
     void setRenderNode(RenderNode* renderNode);
     void setDirty(int left, int top, int right, int bottom);
     void drawFrame(RenderThread* renderThread);
-    void flushStateChanges(RenderThread* renderThread);
 
     virtual void run();
 
 private:
-    enum TaskMode {
-        MODE_INVALID,
-        MODE_FULL,
-        MODE_STATE_ONLY,
-    };
-
-    void postAndWait(RenderThread* renderThread, TaskMode mode);
+    void postAndWait(RenderThread* renderThread);
     bool syncFrameState();
     void unblockUiThread();
     static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
@@ -80,7 +73,6 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    TaskMode mTaskMode;
     sp<RenderNode> mRenderNode;
     Rect mDirty;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 49b9aca..ce490f1 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -75,9 +75,6 @@
 
 void RenderProxy::destroyContext() {
     if (mContext) {
-        // Flush any pending changes to ensure all garbage is destroyed
-        mDrawFrameTask.flushStateChanges(&mRenderThread);
-
         SETUP_TASK(destroyContext);
         args->context = mContext;
         mContext = 0;
@@ -143,43 +140,18 @@
     mDrawFrameTask.drawFrame(&mRenderThread);
 }
 
-CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) {
-    args->context->destroyCanvas();
+CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
+    args->context->destroyCanvasAndSurface();
     return NULL;
 }
 
-void RenderProxy::destroyCanvas() {
-    // If the canvas is being destroyed we won't be drawing again anytime soon
-    // So flush any pending state changes to allow for resource cleanup.
-    mDrawFrameTask.flushStateChanges(&mRenderThread);
-
-    SETUP_TASK(destroyCanvas);
+void RenderProxy::destroyCanvasAndSurface() {
+    SETUP_TASK(destroyCanvasAndSurface);
     args->context = mContext;
-    post(task);
-}
-
-CREATE_BRIDGE2(attachFunctor, CanvasContext* context, Functor* functor) {
-    args->context->attachFunctor(args->functor);
-    return NULL;
-}
-
-void RenderProxy::attachFunctor(Functor* functor) {
-    SETUP_TASK(attachFunctor);
-    args->context = mContext;
-    args->functor = functor;
-    post(task);
-}
-
-CREATE_BRIDGE2(detachFunctor, CanvasContext* context, Functor* functor) {
-    args->context->detachFunctor(args->functor);
-    return NULL;
-}
-
-void RenderProxy::detachFunctor(Functor* functor) {
-    SETUP_TASK(detachFunctor);
-    args->context = mContext;
-    args->functor = functor;
-    post(task);
+    // destroyCanvasAndSurface() needs a fence as when it returns the
+    // underlying BufferQueue is going to be released from under
+    // the render thread.
+    postAndWait(task);
 }
 
 CREATE_BRIDGE2(invokeFunctor, CanvasContext* context, Functor* functor) {
@@ -188,6 +160,7 @@
 }
 
 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
+    ATRACE_CALL();
     SETUP_TASK(invokeFunctor);
     args->context = mContext;
     args->functor = functor;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1ad3c85..a112493 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -65,10 +65,8 @@
     ANDROID_API void setup(int width, int height);
     ANDROID_API void drawDisplayList(RenderNode* displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
-    ANDROID_API void destroyCanvas();
+    ANDROID_API void destroyCanvasAndSurface();
 
-    ANDROID_API void attachFunctor(Functor* functor);
-    ANDROID_API void detachFunctor(Functor* functor);
     ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
 
     ANDROID_API void runWithGlContext(RenderTask* task);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 7f1c5c7..4513ead 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -43,6 +43,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
@@ -528,6 +529,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
 
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         // TODO merge orientation and rotation
@@ -3975,7 +3977,8 @@
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
                 setBluetoothA2dpOnInt(true);
             }
-            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
+            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                            ((device & AudioSystem.DEVICE_IN_ALL_USB) != 0);
             handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
             if (state != 0) {
                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
@@ -4080,20 +4083,41 @@
                         }
                     }
                 }
-            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
-                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
                 state = intent.getIntExtra("state", 0);
+
                 int alsaCard = intent.getIntExtra("card", -1);
                 int alsaDevice = intent.getIntExtra("device", -1);
+
                 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
                                     : "card=" + alsaCard + ";device=" + alsaDevice);
-                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
-                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
-                Log.v(TAG, "Broadcast Receiver: Got "
-                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
-                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
-                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
+
+                // Playback Device
+                device = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
                 setWiredDeviceConnectionState(device, state, params);
+            } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+                state = intent.getIntExtra("state", 0);
+
+                int alsaCard = intent.getIntExtra("card", -1);
+                int alsaDevice = intent.getIntExtra("device", -1);
+                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
+                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
+                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
+
+                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
+                                    : "card=" + alsaCard + ";device=" + alsaDevice);
+
+                // Playback Device
+                if (hasPlayback) {
+                    device = AudioSystem.DEVICE_OUT_USB_DEVICE;
+                    setWiredDeviceConnectionState(device, state, params);
+                }
+
+                // Capture Device
+                if (hasCapture) {
+                    device = AudioSystem.DEVICE_IN_USB_DEVICE;
+                    setWiredDeviceConnectionState(device, state, params);
+                }
             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                 boolean broadcast = false;
                 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
@@ -4199,7 +4223,7 @@
                         mStreamStates[AudioSystem.STREAM_MUSIC], 0);
             }
         }
-    }
+    } // end class AudioServiceBroadcastReceiver
 
     //==========================================================================================
     // RemoteControlDisplay / RemoteControlClient / Remote info
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9c67bae..327c10c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -288,6 +288,8 @@
                                              DEVICE_IN_USB_DEVICE |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
+                                                 DEVICE_IN_USB_DEVICE);
 
     // device states, must match AudioSystem::device_connection_state
     public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 664c707..214306c 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1064,10 +1064,8 @@
     private boolean mHasRemotePlayback;
 
     /**
-     *  The stack of remote control event receivers.
-     *  Code sections and methods that modify the remote control event receiver stack are
-     *  synchronized on mPRStack, but also BEFORE on mFocusLock as any change in either
-     *  stack, audio focus or RC, can lead to a change in the remote control display
+     * The stack of remote control event receivers.
+     * All read and write operations on mPRStack are synchronized.
      */
     private final Stack<PlayerRecord> mPRStack = new Stack<PlayerRecord>();
 
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index 2446c2f..fbf2eab 100644
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -47,6 +47,8 @@
 import android.os.SystemProperties;
 import android.os.Environment;
 
+import libcore.io.IoUtils;
+
 /**
  * The VideoEditor implementation {@hide}
  */
@@ -1859,15 +1861,15 @@
                 }
             }
 
+            FileOutputStream stream = null;
             try {
-                FileOutputStream stream = new FileOutputStream(mProjectPath + "/"
-                                                          + THUMBNAIL_FILENAME);
+                stream = new FileOutputStream(mProjectPath + "/" + THUMBNAIL_FILENAME);
                 projectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                 stream.flush();
-                stream.close();
             } catch (IOException e) {
                 throw new IllegalArgumentException ("Error creating project thumbnail");
             } finally {
+                IoUtils.closeQuietly(stream);
                 projectBitmap.recycle();
             }
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index d157478..89886ef 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,6 +23,7 @@
 import android.hardware.IProCameraCallbacks;
 import android.hardware.IProCameraUser;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -151,21 +152,50 @@
 
     static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
-        @Override
-        public void onCameraError(int errorCode) {
-        }
-
-        @Override
-        public void onCameraIdle() {
-        }
-
-        @Override
-        public void onCaptureStarted(int requestId, long timestamp) {
-        }
-
-        @Override
-        public void onResultReceived(int frameId, CameraMetadataNative result)
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
                 throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
+         * android.hardware.camera2.CaptureResultExtras, long)
+         */
+        public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onResultReceived(
+         * android.hardware.camera2.impl.CameraMetadataNative,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
+         */
+        public void onCameraIdle() throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 5f3ba74..74ce997 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,6 +21,7 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -84,20 +85,50 @@
 
     public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
 
-        @Override
-        public void onCameraError(int errorCode) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onCameraIdle() {
+        /*
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
+         */
+        public void onCameraIdle() throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onCaptureStarted(int requestId, long timestamp) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
+         * android.hardware.camera2.CaptureResultExtras, long)
+         */
+        public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
 
-        @Override
-        public void onResultReceived(int frameId, CameraMetadataNative result) {
+        /*
+         * (non-Javadoc)
+         * @see
+         * android.hardware.camera2.ICameraDeviceCallbacks#onResultReceived(
+         * android.hardware.camera2.impl.CameraMetadataNative,
+         * android.hardware.camera2.CaptureResultExtras)
+         */
+        public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
+                throws RemoteException {
+            // TODO Auto-generated method stub
+
         }
     }
 
@@ -139,7 +170,7 @@
     }
 
     private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
-        int requestId = mCameraUser.submitRequest(request, streaming);
+        int requestId = mCameraUser.submitRequest(request, streaming, null);
         assertTrue(
                 "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
                 requestId >= 0);
@@ -252,13 +283,13 @@
 
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
         CaptureRequest request1 = builder.build();
-        int status = mCameraUser.submitRequest(request1, /* streaming */false);
+        int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
         assertEquals("Expected submitRequest to return BAD_VALUE " +
                 "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
 
         builder.addTarget(mSurface);
         CaptureRequest request2 = builder.build();
-        status = mCameraUser.submitRequest(request2, /* streaming */false);
+        status = mCameraUser.submitRequest(request2, /* streaming */false, null);
         assertEquals("Expected submitRequest to return BAD_VALUE since " +
                 "the target surface wasn't registered with createStream.",
                 CameraBinderTestUtils.BAD_VALUE, status);
@@ -292,15 +323,15 @@
         assertNotSame("Request IDs should be unique for multiple requests", requestId1,
                 requestIdStreaming);
 
-        int status = mCameraUser.cancelRequest(-1);
+        int status = mCameraUser.cancelRequest(-1, null);
         assertEquals("Invalid request IDs should not be cancellable",
                 CameraBinderTestUtils.BAD_VALUE, status);
 
-        status = mCameraUser.cancelRequest(requestId1);
+        status = mCameraUser.cancelRequest(requestId1, null);
         assertEquals("Non-streaming request IDs should not be cancellable",
                 CameraBinderTestUtils.BAD_VALUE, status);
 
-        status = mCameraUser.cancelRequest(requestIdStreaming);
+        status = mCameraUser.cancelRequest(requestIdStreaming, null);
         assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
                 status);
 
@@ -339,7 +370,7 @@
             CameraBinderTestUtils.INVALID_OPERATION, status);
 
         // Test good case, waitUntilIdle when there is no active repeating request
-        status = mCameraUser.cancelRequest(requestIdStreaming);
+        status = mCameraUser.cancelRequest(requestIdStreaming, null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
         status = mCameraUser.waitUntilIdle();
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
@@ -351,16 +382,14 @@
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Test both single request and streaming request.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onResultReceived(
-                eq(requestId1),
-                argThat(matcher));
+                argThat(matcher),
+                any(CaptureResultExtras.class));
 
-        int streamingId = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onResultReceived(
-                        eq(streamingId),
-                        argThat(matcher));
+                        argThat(matcher),
+                        any(CaptureResultExtras.class));
     }
 
     @SmallTest
@@ -372,13 +401,13 @@
         // Test both single request and streaming request.
         int requestId1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
-                eq(requestId1),
+                any(CaptureResultExtras.class),
                 anyLong());
 
         int streamingId = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onCaptureStarted(
-                        eq(streamingId),
+                        any(CaptureResultExtras.class),
                         timestamps.capture());
 
         long timestamp = 0; // All timestamps should be larger than 0.
@@ -401,7 +430,7 @@
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Cancel and make sure we eventually quiesce
-        status = mCameraUser.cancelRequest(streamingId);
+        status = mCameraUser.cancelRequest(streamingId, null);
 
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle();
 
@@ -422,14 +451,14 @@
         int status;
 
         // Initial flush should work
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         // Then set up a stream
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Flush should still be a no-op, really
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         // Submit a few capture requests
@@ -440,7 +469,7 @@
         int requestId5 = submitCameraRequest(request, /* streaming */false);
 
         // Then flush and wait for idle
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle();
@@ -452,7 +481,7 @@
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Then flush and wait for the idle callback
-        status = mCameraUser.flush();
+        status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle();
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c6eda..fb4de9e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -153,3 +153,23 @@
 {
     return static_cast<Sensor const*>(sensor)->getMinDelay();
 }
+
+int ASensor_getFifoMaxEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoMaxEventCount();
+}
+
+int ASensor_getFifoReservedEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoReservedEventCount();
+}
+
+const char* ASensor_getStringType(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getStringType().string();
+}
+
+const char* ASensor_getRequiredPermission(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
+}
diff --git a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index 12f562b..21e21b5 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -24,7 +24,7 @@
     <string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neobnoviť"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo záloh nižšie:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo pre zálohu nižšie:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"Zadajte svoje heslo na šifrovanie zariadenia nižšie."</string>
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"Zadajte svoje heslo na šifrovanie zariadenia nižšie. Bude tiež použité na šifrovanie archívu zálohy."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Zadajte heslo, ktoré sa použije pri šifrovaní údajov úplnej zálohy. Ak pole ponecháte prázdne, použije sa vaše aktuálne heslo zálohy:"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index baca387..28323b6 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -38,7 +38,7 @@
     <string name="save_error" msgid="6167009778003223664">"Impossibile salvare il documento"</string>
     <string name="create_error" msgid="3735649141335444215">"Impossibile creare la cartella"</string>
     <string name="query_error" msgid="1222448261663503501">"Impossibile chiedere documenti"</string>
-    <string name="root_recent" msgid="4470053704320518133">"Recenti"</string>
+    <string name="root_recent" msgid="4470053704320518133">"Recente"</string>
     <string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> liberi"</string>
     <string name="root_type_service" msgid="2178854894416775409">"Servizi di archiviazione"</string>
     <string name="root_type_shortcut" msgid="3318760609471618093">"Scorciatoie"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 42cec9c..f4e5582 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -44,8 +44,8 @@
     <string name="root_type_shortcut" msgid="3318760609471618093">"Skróty"</string>
     <string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
-    <string name="pref_advanced_devices" msgid="903257239609301276">"Pokaż urządzenia zaawansowane"</string>
-    <string name="pref_file_size" msgid="2826879315743961459">"Pokaż rozmiar pliku"</string>
+    <string name="pref_advanced_devices" msgid="903257239609301276">"Wyświetl urządzenia zaawansowane"</string>
+    <string name="pref_file_size" msgid="2826879315743961459">"Wyświetl rozmiar pliku"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"Wyświetl rozmiar urządzenia"</string>
     <string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
diff --git a/packages/FusedLocation/res/values-fr-rCA/strings.xml b/packages/FusedLocation/res/values-fr-rCA/strings.xml
index c7d33af..0d2cccc 100644
--- a/packages/FusedLocation/res/values-fr-rCA/strings.xml
+++ b/packages/FusedLocation/res/values-fr-rCA/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Tables de fusion"</string>
+    <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
 </resources>
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 5b08674..1be44f9 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files) \
                    $(call all-proto-files-under,src)
 
-LOCAL_PACKAGE_NAME := Keyguard
+LOCAL_MODULE := Keyguard
 
 LOCAL_CERTIFICATE := platform
 
@@ -30,6 +30,8 @@
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 
-include $(BUILD_PACKAGE)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-#include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 75b7dbd..352317d 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -44,11 +44,7 @@
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
         android:persistent="true"
-        android:supportsRtl="true"
-        android:requiredForProfile="all">
-
-        <service android:name=".KeyguardService"
-            android:exported="true" />
+        android:supportsRtl="true">
 
     </application>
 </manifest>
diff --git a/packages/Keyguard/res/layout-land/keyguard_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
index 9f1c1f0..1d596d3 100644
--- a/packages/Keyguard/res/layout-land/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
@@ -21,7 +21,7 @@
     and the security view. -->
 <com.android.keyguard.KeyguardHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml
index ebd0a64..49b4212 100644
--- a/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml
+++ b/packages/Keyguard/res/layout-land/keyguard_simple_host_view.xml
@@ -21,7 +21,7 @@
     and the security view. -->
 <com.android.keyguard.KeyguardSimpleHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
diff --git a/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
index da31065..50c2709 100644
--- a/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
+++ b/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
@@ -19,7 +19,7 @@
 
 <!-- This is the selector widget that allows the user to select an action. -->
 <com.android.keyguard.KeyguardWidgetCarousel
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:paddingLeft="25dp"
     android:paddingRight="25dp"
diff --git a/packages/Keyguard/res/layout-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
index 136b296..8223db4 100644
--- a/packages/Keyguard/res/layout-port/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
@@ -21,7 +21,7 @@
     and the security view. -->
 <com.android.keyguard.KeyguardHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
index cba7667..ed600b0 100644
--- a/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
+++ b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
@@ -21,7 +21,7 @@
     and the security view. -->
 <com.android.keyguard.KeyguardSimpleHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
diff --git a/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
index d0a07ca..6d7d864 100644
--- a/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
+++ b/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
@@ -19,7 +19,7 @@
 
 <!-- This is the selector widget that allows the user to select an action. -->
 <com.android.keyguard.KeyguardWidgetPager
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/app_widget_container"
     android:paddingLeft="25dp"
diff --git a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
index 85f6b6d..ba2f3a6 100644
--- a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -21,7 +21,7 @@
     and the security view. -->
 <com.android.keyguard.KeyguardHostView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_host_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_account_view.xml b/packages/Keyguard/res/layout/keyguard_account_view.xml
index 766effa..bde2ec6 100644
--- a/packages/Keyguard/res/layout/keyguard_account_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_account_view.xml
@@ -18,7 +18,7 @@
 -->
 <com.android.keyguard.KeyguardAccountView
     xmlns:android="http://schemas.android.com/apk/res/android"
-	xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+	xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_account_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
new file mode 100644
index 0000000..dedf427
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <View android:id="@+id/bouncer_background"
+        android:background="#aa000000"
+        android:clickable="true"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <include layout="@layout/keyguard_simple_host_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</FrameLayout>
+
diff --git a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
index 94c68a5..8c8ec7a 100644
--- a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
@@ -20,7 +20,7 @@
 <!-- This is the screen that allows the user to unlock by showing their face.  -->
 <com.android.keyguard.KeyguardFaceUnlockView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_face_unlock_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml b/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
index c1d5326..83036ab 100644
--- a/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
+++ b/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
@@ -17,7 +17,7 @@
 */
 -->
 <com.android.keyguard.KeyguardMultiUserSelectorView
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     xmlns:android="http://schemas.android.com/apk/res/android"
     androidprv:layout_childType="userSwitcher"
     android:id="@+id/keyguard_user_selector"
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index d8012bf..ed3f0e0 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -18,7 +18,7 @@
 -->
 <com.android.keyguard.KeyguardPasswordView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_password_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index 0c9380c..3d7820f 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -22,7 +22,7 @@
      is the portrait layout.  -->
 <com.android.keyguard.KeyguardPatternView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_pattern_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_pin_view.xml b/packages/Keyguard/res/layout/keyguard_pin_view.xml
index 00c6a21..a804c8c 100644
--- a/packages/Keyguard/res/layout/keyguard_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pin_view.xml
@@ -19,7 +19,7 @@
 
 <com.android.keyguard.KeyguardPINView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_pin_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_presentation.xml b/packages/Keyguard/res/layout/keyguard_presentation.xml
index 7df0b70..ab676aa 100644
--- a/packages/Keyguard/res/layout/keyguard_presentation.xml
+++ b/packages/Keyguard/res/layout/keyguard_presentation.xml
@@ -20,7 +20,7 @@
 <!-- This is a view that shows general status information in Keyguard. -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/presentation"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
diff --git a/packages/Keyguard/res/layout/keyguard_selector_view.xml b/packages/Keyguard/res/layout/keyguard_selector_view.xml
index 6cb5e67..d3064ed 100644
--- a/packages/Keyguard/res/layout/keyguard_selector_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_selector_view.xml
@@ -20,7 +20,7 @@
 <!-- This is the selector widget that allows the user to select an action. -->
 <com.android.keyguard.KeyguardSelectorView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_selector_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
index eccac19..e96220e 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
@@ -19,7 +19,7 @@
 <!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
 <com.android.keyguard.KeyguardSimPinView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_sim_pin_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
index fe37203..bf15ba0 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
@@ -20,7 +20,7 @@
     carrier-provided PUK code and entering a new SIM PIN for it. -->
 <com.android.keyguard.KeyguardSimPukView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_sim_puk_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_status_area.xml b/packages/Keyguard/res/layout/keyguard_status_area.xml
index 98ba512..2730517 100644
--- a/packages/Keyguard/res/layout/keyguard_status_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_area.xml
@@ -20,7 +20,7 @@
 <!-- This is a view that shows general status information in Keyguard. -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index a4d298a..3b3a069 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -18,43 +18,38 @@
 -->
 
 <!-- This is a view that shows general status information in Keyguard. -->
-<com.android.keyguard.KeyguardWidgetFrame
+<com.android.keyguard.KeyguardStatusView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
     android:id="@+id/keyguard_status_view"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center">
-
-    <com.android.keyguard.KeyguardStatusView
-        android:id="@+id/keyguard_status_view_face_palm"
-        android:orientation="vertical"
+    android:gravity="center_horizontal|top"
+    android:layout_marginTop="32dp"
+    android:layout_marginBottom="32dp"
+    android:contentDescription="@string/keyguard_accessibility_status">
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center_horizontal|top"
-        android:contentDescription="@string/keyguard_accessibility_status">
-        <LinearLayout
-            android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|top"
+        android:orientation="vertical"
+        android:focusable="true">
+        <TextClock
+            android:id="@+id/clock_view"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal|top"
-            android:orientation="vertical"
-            android:focusable="true">
-            <TextClock
-                android:id="@+id/clock_view"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal|top"
-                android:textColor="@color/clock_white"
-                android:singleLine="true"
-                style="@style/widget_big_thin"
-                android:format12Hour="@string/keyguard_widget_12_hours_format"
-                android:format24Hour="@string/keyguard_widget_24_hours_format"
-                android:baselineAligned="true"
-                android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
+            android:textColor="@color/clock_white"
+            android:singleLine="true"
+            style="@style/widget_big_thin"
+            android:format12Hour="@string/keyguard_widget_12_hours_format"
+            android:format24Hour="@string/keyguard_widget_24_hours_format"
+            android:baselineAligned="true"
+            android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
 
-            <include layout="@layout/keyguard_status_area" />
-        </LinearLayout>
-    </com.android.keyguard.KeyguardStatusView>
-</com.android.keyguard.KeyguardWidgetFrame>
+        <include layout="@layout/keyguard_status_area" />
+    </LinearLayout>
+</com.android.keyguard.KeyguardStatusView>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 89ac293..cdf8ca9 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -35,7 +35,7 @@
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Pripojte nabíjačku."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Telefón odomknete stlačením tlačidla Menu."</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Sieť je zablokovaná"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM."</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tablete nie je žiadna karta SIM."</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefóne nie je žiadna karta SIM."</string>
     <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vložte kartu SIM."</string>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index c775467..19eb4c5 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -75,7 +75,7 @@
     <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Bài hát được đánh dấu không thích"</string>
     <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Trái tim"</string>
     <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Mở khóa để tiếp tục"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Quá trình chạy bị hủy"</string>
+    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Quá trình khởi chạy bị hủy"</string>
     <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Thả <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> để xóa."</string>
     <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> sẽ không bị xóa."</string>
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 71e9924..c05f834 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -158,7 +158,7 @@
     <dimen name="bottom_text_spacing_digital">-8dp</dimen>
     <dimen name="label_font_size">14dp</dimen>
     <dimen name="widget_label_font_size">14dp</dimen>
-    <dimen name="widget_big_font_size">80dp</dimen>
+    <dimen name="widget_big_font_size">60dp</dimen>
     <dimen name="big_font_size">120dp</dimen>
 
 </resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 4738049..d20b269 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -18,6 +18,8 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- App label in the manifest  -->
+    <string name="app_name">Keyguard</string>
     <!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
          Displayed in one line in a large font.  -->
     <string name="keyguard_password_enter_pin_code">Type PIN code</string>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index 80fcf75..4a034aa 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -56,8 +56,7 @@
     <!-- Built-in clock widget stuff -->
     <style name="widget_label">
         <item name="android:textStyle">bold</item>
-        <item name="android:textAllCaps">true</item>
-        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:fontFamily">sans-serif-light</item>
         <item name="android:textSize">@dimen/widget_label_font_size</item>
     </style>
     <style name="big_thin">
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
index 74e6f33..2bf74ea 100644
--- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
@@ -38,7 +38,7 @@
 
 public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
     private static final String TAG = CameraWidgetFrame.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final int WIDGET_ANIMATION_DURATION = 250; // ms
     private static final int WIDGET_WAIT_DURATION = 400; // ms
     private static final int RECOVERY_DELAY = 1000; // ms
@@ -113,12 +113,14 @@
 
     private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         private boolean mShowing;
-        void onKeyguardVisibilityChanged(boolean showing) {
+
+        @Override
+        public void onKeyguardVisibilityChanged(boolean showing) {
             if (mShowing == showing)
                 return;
             mShowing = showing;
             CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing);
-        };
+        }
     };
 
     private static final class FixedSizeFrameLayout extends FrameLayout {
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index fd56613..4ed37d4 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -48,10 +48,11 @@
             updateEmergencyCallButton(simState, phoneState);
         }
 
-        void onPhoneStateChanged(int phoneState) {
+        @Override
+        public void onPhoneStateChanged(int phoneState) {
             State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
             updateEmergencyCallButton(simState, phoneState);
-        };
+        }
     };
     private LockPatternUtils mLockPatternUtils;
     private PowerManager mPowerManager;
diff --git a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
index de839c6..2f14003 100644
--- a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
+++ b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
@@ -37,8 +37,9 @@
 
 public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
 
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "FULLockscreen";
+    private static final String FACE_LOCK_PACKAGE = "com.android.facelock";
 
     private final Context mContext;
     private final LockPatternUtils mLockPatternUtils;
@@ -128,7 +129,8 @@
         if (!mBoundToService) {
             Log.d(TAG, "Binding to Face Unlock service for user="
                     + mLockPatternUtils.getCurrentUser());
-            mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()),
+            mContext.bindServiceAsUser(
+                    new Intent(IFaceLockInterface.class.getName()).setPackage(FACE_LOCK_PACKAGE),
                     mConnection,
                     Context.BIND_AUTO_CREATE,
                     new UserHandle(mLockPatternUtils.getCurrentUser()));
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 3950159..4b386b6 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -231,7 +231,7 @@
     @Override
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         if (mCallback != null) {
-            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
+            mCallback.userActivity(KeyguardConstants.DIGIT_PRESS_WAKE_MILLIS);
         }
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
index 0d5e477..25f3383 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
@@ -43,7 +43,7 @@
 
 public abstract class KeyguardActivityLauncher {
     private static final String TAG = KeyguardActivityLauncher.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
     private static final Intent SECURE_CAMERA_INTENT =
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java b/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java
new file mode 100644
index 0000000..bfa95f38
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 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.keyguard;
+
+/**
+ * Defines constants for the Keyguard.
+ */
+public class KeyguardConstants {
+
+    /**
+     * Turns on debugging information for the whole Keyguard. This is very verbose and should only
+     * be used temporarily for debugging.
+     */
+    public static final boolean DEBUG = false;
+
+    /** Timeout used for key presses. */
+    public static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
index 6bcbd6c..55f965c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -30,18 +30,18 @@
 
 public class KeyguardDisplayManager {
     protected static final String TAG = "KeyguardDisplayManager";
-    private static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static boolean DEBUG = KeyguardConstants.DEBUG;
     Presentation mPresentation;
     private MediaRouter mMediaRouter;
     private Context mContext;
     private boolean mShowing;
 
-    KeyguardDisplayManager(Context context) {
+    public KeyguardDisplayManager(Context context) {
         mContext = context;
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
     }
 
-    void show() {
+    public void show() {
         if (!mShowing) {
             if (DEBUG) Slog.v(TAG, "show");
             mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
@@ -51,7 +51,7 @@
         mShowing = true;
     }
 
-    void hide() {
+    public void hide() {
         if (mShowing) {
             if (DEBUG) Slog.v(TAG, "hide");
             mMediaRouter.removeCallback(mMediaRouterCallback);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index c2cd32f..900d16e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -36,7 +36,7 @@
 public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
 
     private static final String TAG = "FULKeyguardFaceUnlockView";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private KeyguardSecurityCallback mKeyguardSecurityCallback;
     private LockPatternUtils mLockPatternUtils;
     private BiometricSensorUnlock mBiometricUnlock;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 2e76f19..7cfd684 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -61,7 +61,7 @@
 
 public class KeyguardHostView extends KeyguardViewBase {
     private static final String TAG = "KeyguardHostView";
-    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static boolean DEBUG = KeyguardConstants.DEBUG;
     public static boolean DEBUGXPORT = true; // debug music transport control
 
     // Transport control states.
@@ -118,7 +118,7 @@
         void userActivity();
     }
 
-    /*package*/ interface OnDismissAction {
+    public interface OnDismissAction {
         /* returns true if the dismiss should be deferred */
         boolean onDismiss();
     }
@@ -241,7 +241,7 @@
             }
         }
         @Override
-        void onMusicClientIdChanged(
+        public void onMusicClientIdChanged(
                 int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
             // Set transport state to invisible until we know music is playing (below)
             if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
@@ -449,7 +449,7 @@
     }
 
     @Override
-    protected void setLockPatternUtils(LockPatternUtils utils) {
+    public void setLockPatternUtils(LockPatternUtils utils) {
         super.setLockPatternUtils(utils);
         getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
index aa2ae0e..3aec55c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
@@ -37,7 +37,7 @@
 
 class KeyguardMultiUserAvatar extends FrameLayout {
     private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
 
     private ImageView mUserImage;
     private TextView mUserName;
@@ -123,7 +123,7 @@
         mUserName = (TextView) findViewById(R.id.keyguard_user_name);
 
         mFramed = (KeyguardCircleFramedDrawable)
-                KeyguardViewMediator.getAvatarCache().get(user.id);
+                MultiUserAvatarCache.getInstance().get(user.id);
 
         // If we can't find it or the params don't match, create the drawable again
         if (mFramed == null
@@ -143,7 +143,7 @@
 
             mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
                     mFrameShadowColor, mShadowRadius, mHighlightColor);
-            KeyguardViewMediator.getAvatarCache().put(user.id, mFramed);
+            MultiUserAvatarCache.getInstance().put(user.id, mFramed);
         }
 
         mFramed.reset();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 14de6dd..b4308c6 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -44,7 +44,7 @@
 public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
 
     private static final String TAG = "SecurityPatternView";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
 
     // how long before we clear the wrong pattern
     private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 0f62100..8425c48 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -30,7 +30,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 
 public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
-    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "KeyguardSecurityView";
     private KeyguardSecurityModel mSecurityModel;
     private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 70a0e44..07239d1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -38,7 +38,7 @@
  */
 public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView {
     private static final String TAG = "KeyguardSecurityViewFlipper";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
 
     private Rect mTempRect = new Rect();
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
index 97aec68..03e7b07 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java
@@ -36,7 +36,6 @@
 import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
 
 public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView {
-    private static final boolean DEBUG = KeyguardHostView.DEBUG;
     private static final String TAG = "SecuritySelectorView";
     private static final String ASSIST_ICON_METADATA_NAME =
         "com.android.systemui.action_assist_icon";
@@ -57,12 +56,10 @@
         public void onTrigger(View v, int target) {
             final int resId = mGlowPadView.getResourceIdForTarget(target);
 
-            switch (resId) {
-                case R.drawable.ic_lockscreen_unlock_phantom:
-                case R.drawable.ic_lockscreen_unlock:
-                    mCallback.userActivity(0);
-                    mCallback.dismiss(false);
-                break;
+            if (resId == R.drawable.ic_lockscreen_unlock_phantom
+                    || resId == R.drawable.ic_lockscreen_unlock) {
+                mCallback.userActivity(0);
+                mCallback.dismiss(false);
             }
         }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index ae7ac97..d6a4f52 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -41,7 +41,7 @@
 public class KeyguardSimPinView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
     private static final String LOG_TAG = "KeyguardSimPinView";
-    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     public static final String TAG = "KeyguardSimPinView";
 
     private ProgressDialog mSimUnlockProgressDialog = null;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index ca4f811..04cbde1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -42,7 +42,7 @@
 public class KeyguardSimPukView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
     private static final String LOG_TAG = "KeyguardSimPukView";
-    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     public static final String TAG = "KeyguardSimPukView";
 
     private ProgressDialog mSimUnlockProgressDialog = null;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
index cf983cb..5d5168c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -38,11 +38,6 @@
     }
 
     @Override
-    public void verifyUnlock() {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void cleanUp() {
         // TODO Auto-generated method stub
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 0bfee38..ae55c4a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -33,7 +33,7 @@
 import java.util.Locale;
 
 public class KeyguardStatusView extends GridLayout {
-    private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "KeyguardStatusView";
 
     private LockPatternUtils mLockPatternUtils;
@@ -50,22 +50,22 @@
         }
 
         @Override
-        void onKeyguardVisibilityChanged(boolean showing) {
+        public void onKeyguardVisibilityChanged(boolean showing) {
             if (showing) {
                 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
                 refresh();
             }
-        };
+        }
 
         @Override
         public void onScreenTurnedOn() {
             setEnableMarquee(true);
-        };
+        }
 
         @Override
         public void onScreenTurnedOff(int why) {
             setEnableMarquee(false);
-        };
+        }
     };
 
     public KeyguardStatusView(Context context) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
index a7cd909..0d472ae 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -60,7 +60,7 @@
 public class KeyguardTransportControlView extends FrameLayout {
 
     private static final int RESET_TO_METADATA_DELAY = 5000;
-    protected static final boolean DEBUG = false;
+    protected static final boolean DEBUG = KeyguardConstants.DEBUG;
     protected static final String TAG = "TransportControlView";
 
     private static final boolean ANIMATE_TRANSITIONS = true;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 88c78ab..73c2840 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -72,7 +72,7 @@
 public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
 
     private static final String TAG = "KeyguardUpdateMonitor";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_SIM_STATES = DEBUG || false;
     private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
     private static final int LOW_BATTERY_THRESHOLD = 20;
@@ -679,7 +679,7 @@
      * broadcast and hence not handle the event. This method is ultimately called by
      * PhoneWindowManager in this case.
      */
-    protected void dispatchBootCompleted() {
+    public void dispatchBootCompleted() {
         mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 556711b..862931e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -20,7 +20,7 @@
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.os.SystemClock;
-import android.util.Log;
+import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicy;
 
 import com.android.internal.telephony.IccCardConstants;
@@ -28,7 +28,7 @@
 /**
  * Callback for general information relevant to lock screen.
  */
-class KeyguardUpdateMonitorCallback {
+public class KeyguardUpdateMonitorCallback {
 
     private static final long VISIBILITY_CHANGED_COLLAPSE_MS = 1000;
     private long mVisibilityChangedCalled;
@@ -40,12 +40,12 @@
      *
      * @param status current battery status
      */
-    void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { }
+    public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { }
 
     /**
      * Called once per minute or when the time changes.
      */
-    void onTimeChanged() { }
+    public void onTimeChanged() { }
 
     /**
      * Called when the carrier PLMN or SPN changes.
@@ -54,14 +54,14 @@
      *   be displayed.
      * @param spn The service provider name.  May be null if it shouldn't be displayed.
      */
-    void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { }
+    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { }
 
     /**
      * Called when the ringer mode changes.
      * @param state the current ringer state, as defined in
      * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
      */
-    void onRingerModeChanged(int state) { }
+    public void onRingerModeChanged(int state) { }
 
     /**
      * Called when the phone state changes. String will be one of:
@@ -69,15 +69,15 @@
      * {@link TelephonyManager@EXTRA_STATE_RINGING}
      * {@link TelephonyManager#EXTRA_STATE_OFFHOOK
      */
-    void onPhoneStateChanged(int phoneState) { }
+    public void onPhoneStateChanged(int phoneState) { }
 
     /**
      * Called when the visibility of the keyguard changes.
      * @param showing Indicates if the keyguard is now visible.
      */
-    void onKeyguardVisibilityChanged(boolean showing) { }
+    public void onKeyguardVisibilityChanged(boolean showing) { }
 
-    void onKeyguardVisibilityChangedRaw(boolean showing) {
+    public void onKeyguardVisibilityChangedRaw(boolean showing) {
         final long now = SystemClock.elapsedRealtime();
         if (showing == mShowing
                 && (now - mVisibilityChangedCalled) < VISIBILITY_CHANGED_COLLAPSE_MS) return;
@@ -90,44 +90,44 @@
      * Called when visibility of lockscreen clock changes, such as when
      * obscured by a widget.
      */
-    void onClockVisibilityChanged() { }
+    public void onClockVisibilityChanged() { }
 
     /**
      * Called when the device becomes provisioned
      */
-    void onDeviceProvisioned() { }
+    public void onDeviceProvisioned() { }
 
     /**
      * Called when the device policy changes.
      * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
      */
-    void onDevicePolicyManagerStateChanged() { }
+    public void onDevicePolicyManagerStateChanged() { }
 
     /**
      * Called when the user change begins.
      */
-    void onUserSwitching(int userId) { }
+    public void onUserSwitching(int userId) { }
 
     /**
      * Called when the user change is complete.
      */
-    void onUserSwitchComplete(int userId) { }
+    public void onUserSwitchComplete(int userId) { }
 
     /**
      * Called when the SIM state changes.
      * @param simState
      */
-    void onSimStateChanged(IccCardConstants.State simState) { }
+    public void onSimStateChanged(IccCardConstants.State simState) { }
 
     /**
      * Called when a user is removed.
      */
-    void onUserRemoved(int userId) { }
+    public void onUserRemoved(int userId) { }
 
     /**
      * Called when the user's info changed.
      */
-    void onUserInfoChanged(int userId) { }
+    public void onUserInfoChanged(int userId) { }
 
     /**
      * Called when boot completed.
@@ -135,12 +135,12 @@
      * Note, this callback will only be received if boot complete occurs after registering with
      * KeyguardUpdateMonitor.
      */
-    void onBootCompleted() { }
+    public void onBootCompleted() { }
 
     /**
      * Called when audio client attaches or detaches from AudioManager.
      */
-    void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
+    public void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
 
     /**
      * Called when the audio playback state changes.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index 78f4506..bc0f364 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -60,7 +60,7 @@
 
     private AudioManager mAudioManager;
     private TelephonyManager mTelephonyManager = null;
-    protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+    protected ViewMediatorCallback mViewMediatorCallback;
     protected LockPatternUtils mLockPatternUtils;
     private OnDismissAction mDismissAction;
 
@@ -68,7 +68,7 @@
     // they will be handled here for specific media types such as music, otherwise
     // the audio service will bring up the volume dialog.
     private static final boolean KEYGUARD_MANAGES_VOLUME = true;
-    private static final boolean DEBUG = false;
+    public static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "KeyguardViewBase";
 
     private KeyguardSecurityContainer mSecurityContainer;
@@ -107,7 +107,6 @@
         mSecurityContainer.setSecurityCallback(this);
         mSecurityContainer.showPrimarySecurityScreen(false);
         // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
-        setBackButtonEnabled(false);
     }
 
     /**
@@ -120,15 +119,11 @@
 
     /**
      *  Dismisses the keyguard by going to the next screen or making it gone.
+     *
+     *  @return True if the keyguard is done.
      */
-    public void dismiss() {
-        dismiss(false);
-    }
-
-    private void setBackButtonEnabled(boolean enabled) {
-        setSystemUiVisibility(enabled ?
-                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
-                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+    public boolean dismiss() {
+        return dismiss(false);
     }
 
     protected void showBouncer(boolean show) {
@@ -141,8 +136,7 @@
 
     public boolean handleBackKey() {
         if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
-            // go back to primary screen and re-disable back
-            setBackButtonEnabled(false);
+            // go back to primary screen
             mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
             return true;
         }
@@ -205,12 +199,6 @@
 
     @Override
     public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
-        // Enable or disable the back button based on security mode
-        if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
-            // we're showing account as a backup, provide a way to get back to primary
-            setBackButtonEnabled(true);
-        }
-
         if (mViewMediatorCallback != null) {
             mViewMediatorCallback.setNeedsInput(needsInput);
         }
@@ -231,7 +219,7 @@
     /**
      * Called when the screen turned off.
      */
-    protected void onScreenTurnedOff() {
+    public void onScreenTurnedOff() {
         if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
                 Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
         // Once the screen turns off, we no longer consider this to be first boot and we want the
@@ -245,7 +233,7 @@
     /**
      * Called when the screen turned on.
      */
-    protected void onScreenTurnedOn() {
+    public void onScreenTurnedOn() {
         if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
         mSecurityContainer.showPrimarySecurityScreen(false);
         mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
@@ -433,8 +421,7 @@
         return false;
     }
 
-    public void setViewMediatorCallback(
-            KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
+    public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
         mViewMediatorCallback = viewMediatorCallback;
         // Update ViewMediator with the current input method requirements
         mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
@@ -484,7 +471,7 @@
         mActivityLauncher.launchCamera(getHandler(), null);
     }
 
-    protected void setLockPatternUtils(LockPatternUtils utils) {
+    public void setLockPatternUtils(LockPatternUtils utils) {
         mLockPatternUtils = utils;
         mSecurityContainer.setLockPatternUtils(utils);
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
deleted file mode 100644
index 5b35ba88..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-
-import com.android.internal.policy.IKeyguardShowCallback;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.analytics.KeyguardAnalytics;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-/**
- * Manages creating, showing, hiding and resetting the keyguard.  Calls back
- * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
- * the wake lock and report that the keyguard is done, which is in turn,
- * reported to this class by the current {@link KeyguardViewBase}.
- */
-public class KeyguardViewManager {
-    private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
-    private static String TAG = "KeyguardViewManager";
-    public final static String IS_SWITCHING_USER = "is_switching_user";
-
-    // Delay dismissing keyguard to allow animations to complete.
-    private static final int HIDE_KEYGUARD_DELAY = 500;
-
-    // Timeout used for keypresses
-    static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
-    private static final boolean ENABLE_SIMPLE_KEYGUARD = false;
-
-    private final Context mContext;
-    private final ViewManager mViewManager;
-    private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
-    private final KeyguardAnalytics.Callback mAnalyticsCallback;
-
-    private WindowManager.LayoutParams mWindowLayoutParams;
-    private boolean mNeedsInput = false;
-
-    private ViewManagerHost mKeyguardHost;
-    private KeyguardViewBase mKeyguardView;
-
-    private boolean mScreenOn = false;
-    private LockPatternUtils mLockPatternUtils;
-
-    private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onSetBackground(Bitmap bmp) {
-            mKeyguardHost.setCustomBackground(bmp != null ?
-                    new BitmapDrawable(mContext.getResources(), bmp) : null);
-            updateShowWallpaper(bmp == null);
-        }
-    };
-
-    public interface ShowListener {
-        void onShown(IBinder windowToken);
-    };
-
-    /**
-     * @param context Used to create views.
-     * @param viewManager Keyguard will be attached to this.
-     * @param callback Used to notify of changes.
-     * @param lockPatternUtils
-     */
-    public KeyguardViewManager(Context context, ViewManager viewManager,
-            KeyguardViewMediator.ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, KeyguardAnalytics.Callback analyticsCallback) {
-        mContext = context;
-        mViewManager = viewManager;
-        mViewMediatorCallback = callback;
-        mLockPatternUtils = lockPatternUtils;
-        mAnalyticsCallback = analyticsCallback;
-    }
-
-    /**
-     * Show the keyguard.  Will handle creating and attaching to the view manager
-     * lazily.
-     */
-    public synchronized void show(Bundle options) {
-        if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
-        if (mAnalyticsCallback != null) {
-            mAnalyticsCallback.onShow();
-        }
-
-        boolean enableScreenRotation = shouldEnableScreenRotation();
-
-        maybeCreateKeyguardLocked(enableScreenRotation, false, options);
-        maybeEnableScreenRotation(enableScreenRotation);
-
-        // Disable common aspects of the system/status/navigation bars that are not appropriate or
-        // useful on any keyguard screen but can be re-shown by dialogs or SHOW_WHEN_LOCKED
-        // activities. Other disabled bits are handled by the KeyguardViewMediator talking
-        // directly to the status bar service.
-        int visFlags = View.STATUS_BAR_DISABLE_HOME;
-        if (shouldEnableTranslucentDecor()) {
-            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
-                                       | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-        }
-        if (DEBUG) Log.v(TAG, "show:setSystemUiVisibility(" + Integer.toHexString(visFlags)+")");
-        mKeyguardHost.setSystemUiVisibility(visFlags);
-
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-        mKeyguardHost.setVisibility(View.VISIBLE);
-        mKeyguardView.show();
-        mKeyguardView.requestFocus();
-    }
-
-    private boolean shouldEnableScreenRotation() {
-        Resources res = mContext.getResources();
-        return SystemProperties.getBoolean("lockscreen.rot_override",false)
-                || res.getBoolean(R.bool.config_enableLockScreenRotation);
-    }
-
-    private boolean shouldEnableTranslucentDecor() {
-        Resources res = mContext.getResources();
-        return res.getBoolean(R.bool.config_enableLockScreenTranslucentDecor);
-    }
-
-    class ViewManagerHost extends FrameLayout {
-        private static final int BACKGROUND_COLOR = 0x70000000;
-
-        private Drawable mCustomBackground;
-
-        // This is a faster way to draw the background on devices without hardware acceleration
-        private final Drawable mBackgroundDrawable = new Drawable() {
-            @Override
-            public void draw(Canvas canvas) {
-                if (mCustomBackground != null) {
-                    final Rect bounds = mCustomBackground.getBounds();
-                    final int vWidth = getWidth();
-                    final int vHeight = getHeight();
-
-                    final int restore = canvas.save();
-                    canvas.translate(-(bounds.width() - vWidth) / 2,
-                            -(bounds.height() - vHeight) / 2);
-                    mCustomBackground.draw(canvas);
-                    canvas.restoreToCount(restore);
-                } else {
-                    canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
-                }
-            }
-
-            @Override
-            public void setAlpha(int alpha) {
-            }
-
-            @Override
-            public void setColorFilter(ColorFilter cf) {
-            }
-
-            @Override
-            public int getOpacity() {
-                return PixelFormat.TRANSLUCENT;
-            }
-        };
-
-        public ViewManagerHost(Context context) {
-            super(context);
-            setBackground(mBackgroundDrawable);
-        }
-
-        public void setCustomBackground(Drawable d) {
-            mCustomBackground = d;
-            if (d != null) {
-                d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
-            }
-            computeCustomBackgroundBounds();
-            invalidate();
-        }
-
-        private void computeCustomBackgroundBounds() {
-            if (mCustomBackground == null) return; // Nothing to do
-            if (!isLaidOut()) return; // We'll do this later
-
-            final int bgWidth = mCustomBackground.getIntrinsicWidth();
-            final int bgHeight = mCustomBackground.getIntrinsicHeight();
-            final int vWidth = getWidth();
-            final int vHeight = getHeight();
-
-            final float bgAspect = (float) bgWidth / bgHeight;
-            final float vAspect = (float) vWidth / vHeight;
-
-            if (bgAspect > vAspect) {
-                mCustomBackground.setBounds(0, 0, (int) (vHeight * bgAspect), vHeight);
-            } else {
-                mCustomBackground.setBounds(0, 0, vWidth, (int) (vWidth / bgAspect));
-            }
-        }
-
-        @Override
-        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-            super.onSizeChanged(w, h, oldw, oldh);
-            computeCustomBackgroundBounds();
-        }
-
-        @Override
-        protected void onConfigurationChanged(Configuration newConfig) {
-            super.onConfigurationChanged(newConfig);
-            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                // only propagate configuration messages if we're currently showing
-                maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, null);
-            } else {
-                if (DEBUG) Log.v(TAG, "onConfigurationChanged: view not visible");
-            }
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            if (mKeyguardView != null) {
-                // Always process back and menu keys, regardless of focus
-                if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                    int keyCode = event.getKeyCode();
-                    if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
-                        return true;
-                    } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
-                        return true;
-                    }
-                }
-                // Always process media keys, regardless of focus
-                if (mKeyguardView.dispatchKeyEvent(event)) {
-                    return true;
-                }
-            }
-            return super.dispatchKeyEvent(event);
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent ev) {
-            boolean result = false;
-            if (mAnalyticsCallback != null) {
-                result = mAnalyticsCallback.onTouchEvent(ev, getWidth(), getHeight()) || result;
-            }
-            return super.dispatchTouchEvent(ev) || result;
-        }
-    }
-
-    SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
-    private int mCurrentLayout;
-
-    private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
-            Bundle options) {
-        if (mKeyguardHost != null) {
-            mKeyguardHost.saveHierarchyState(mStateContainer);
-        }
-
-        if (mKeyguardHost == null) {
-            if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
-
-            mKeyguardHost = new ViewManagerHost(mContext);
-
-            int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
-                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-
-            if (!mNeedsInput) {
-                flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            }
-
-            final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
-            final int type = WindowManager.LayoutParams.TYPE_KEYGUARD;
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
-            lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-            lp.windowAnimations = R.style.Animation_LockScreen;
-            lp.screenOrientation = enableScreenRotation ?
-                    ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-
-            if (ActivityManager.isHighEndGfx()) {
-                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-                lp.privateFlags |=
-                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
-            }
-            lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
-            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
-            lp.setTitle("Keyguard");
-            mWindowLayoutParams = lp;
-            mViewManager.addView(mKeyguardHost, lp);
-
-            KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);
-        }
-
-        if (force || mKeyguardView == null) {
-            mKeyguardHost.setCustomBackground(null);
-            mKeyguardHost.removeAllViews();
-            int layout = (allowNotificationsOnSecureKeyguard() && ENABLE_SIMPLE_KEYGUARD)
-                    ? R.layout.keyguard_simple_host_view
-                    : R.layout.keyguard_host_view;
-            if (mCurrentLayout != layout) {
-                mStateContainer.clear(); // don't restore to the wrong view hierarchy
-                mCurrentLayout = layout;
-            }
-            mKeyguardView = inflateKeyguardView(options, layout);
-            mKeyguardView.requestFocus();
-        }
-        updateUserActivityTimeoutInWindowLayoutParams();
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-
-        mKeyguardHost.restoreHierarchyState(mStateContainer);
-    }
-
-    private boolean allowNotificationsOnSecureKeyguard() {
-        ContentResolver cr = mContext.getContentResolver();
-        return Settings.Global.getInt(cr, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) == 1;
-    }
-
-    private KeyguardViewBase inflateKeyguardView(Bundle options, int layoutId) {
-        View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
-        if (v != null) {
-            mKeyguardHost.removeView(v);
-        }
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        View view = inflater.inflate(layoutId, mKeyguardHost, true);
-        KeyguardViewBase keyguard = (KeyguardViewBase) view.findViewById(R.id.keyguard_host_view);
-        keyguard.setLockPatternUtils(mLockPatternUtils);
-        keyguard.setViewMediatorCallback(mViewMediatorCallback);
-        keyguard.onUserSwitching(options != null && options.getBoolean(IS_SWITCHING_USER));
-        keyguard.onCreateOptions(options);
-        return keyguard;
-    }
-
-    public void updateUserActivityTimeout() {
-        updateUserActivityTimeoutInWindowLayoutParams();
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-    }
-
-    private void updateUserActivityTimeoutInWindowLayoutParams() {
-        // Use the user activity timeout requested by the keyguard view, if any.
-        if (mKeyguardView != null) {
-            long timeout = mKeyguardView.getUserActivityTimeout();
-            if (timeout >= 0) {
-                mWindowLayoutParams.userActivityTimeout = timeout;
-                return;
-            }
-        }
-
-        // Otherwise, use the default timeout.
-        mWindowLayoutParams.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
-    }
-
-    private void maybeEnableScreenRotation(boolean enableScreenRotation) {
-        // TODO: move this outside
-        if (enableScreenRotation) {
-            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
-            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
-        } else {
-            if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
-            mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-        }
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-    }
-
-    void updateShowWallpaper(boolean show) {
-        if (show) {
-            mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        } else {
-            mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        }
-        mWindowLayoutParams.format = show ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
-
-        mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-    }
-
-    public void setNeedsInput(boolean needsInput) {
-        mNeedsInput = needsInput;
-        if (mWindowLayoutParams != null) {
-            if (needsInput) {
-                mWindowLayoutParams.flags &=
-                    ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            } else {
-                mWindowLayoutParams.flags |=
-                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-            }
-
-            try {
-                mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-            } catch (java.lang.IllegalArgumentException e) {
-                // TODO: Ensure this method isn't called on views that are changing...
-                Log.w(TAG,"Can't update input method on " + mKeyguardHost + " window not attached");
-            }
-        }
-    }
-
-    /**
-     * Reset the state of the view.
-     */
-    public synchronized void reset(Bundle options) {
-        if (DEBUG) Log.d(TAG, "reset()");
-        // User might have switched, check if we need to go back to keyguard
-        // TODO: It's preferable to stay and show the correct lockscreen or unlock if none
-        maybeCreateKeyguardLocked(shouldEnableScreenRotation(), true, options);
-    }
-
-    public synchronized void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
-        mScreenOn = false;
-        if (mKeyguardView != null) {
-            mKeyguardView.onScreenTurnedOff();
-        }
-    }
-
-    public synchronized void onScreenTurnedOn(final IKeyguardShowCallback callback) {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
-        mScreenOn = true;
-
-        // If keyguard is not showing, we need to inform PhoneWindowManager with a null
-        // token so it doesn't wait for us to draw...
-        final IBinder token = isShowing() ? mKeyguardHost.getWindowToken() : null;
-
-        if (DEBUG && token == null) Slog.v(TAG, "send wm null token: "
-                + (mKeyguardHost == null ? "host was null" : "not showing"));
-
-        if (mKeyguardView != null) {
-            mKeyguardView.onScreenTurnedOn();
-
-            // Caller should wait for this window to be shown before turning
-            // on the screen.
-            if (callback != null) {
-                if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                    // Keyguard may be in the process of being shown, but not yet
-                    // updated with the window manager...  give it a chance to do so.
-                    mKeyguardHost.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                callback.onShown(token);
-                            } catch (RemoteException e) {
-                                Slog.w(TAG, "Exception calling onShown():", e);
-                            }
-                        }
-                    });
-                } else {
-                    try {
-                        callback.onShown(token);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Exception calling onShown():", e);
-                    }
-                }
-            }
-        } else if (callback != null) {
-            try {
-                callback.onShown(token);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Exception calling onShown():", e);
-            }
-        }
-        if (mAnalyticsCallback != null) {
-            mAnalyticsCallback.onScreenOn();
-        }
-    }
-
-    public synchronized void verifyUnlock() {
-        if (DEBUG) Log.d(TAG, "verifyUnlock()");
-        show(null);
-        mKeyguardView.verifyUnlock();
-    }
-
-    /**
-     * Hides the keyguard view
-     */
-    public synchronized void hide() {
-        if (DEBUG) Log.d(TAG, "hide()");
-
-        if (mAnalyticsCallback != null) {
-            mAnalyticsCallback.onHide();
-        }
-
-        if (mKeyguardHost != null) {
-            mKeyguardHost.setVisibility(View.GONE);
-
-            // We really only want to preserve keyguard state for configuration changes. Hence
-            // we should clear state of widgets (e.g. Music) when we hide keyguard so it can
-            // start with a fresh state when we return.
-            mStateContainer.clear();
-
-            // Don't do this right away, so we can let the view continue to animate
-            // as it goes away.
-            if (mKeyguardView != null) {
-                final KeyguardViewBase lastView = mKeyguardView;
-                mKeyguardView = null;
-                mKeyguardHost.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (KeyguardViewManager.this) {
-                            lastView.cleanUp();
-                            // Let go of any large bitmaps.
-                            mKeyguardHost.setCustomBackground(null);
-                            updateShowWallpaper(true);
-                            mKeyguardHost.removeView(lastView);
-                            mViewMediatorCallback.keyguardGone();
-                        }
-                    }
-                }, HIDE_KEYGUARD_DELAY);
-            }
-        }
-    }
-
-    /**
-     * Dismisses the keyguard by going to the next screen or making it gone.
-     */
-    public synchronized void dismiss() {
-        if (mScreenOn) {
-            mKeyguardView.dismiss();
-        }
-    }
-
-    /**
-     * @return Whether the keyguard is showing
-     */
-    public synchronized boolean isShowing() {
-        return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
-    }
-
-    public void showAssistant() {
-        if (mKeyguardView != null) {
-            mKeyguardView.showAssistant();
-        }
-    }
-
-    public void dispatch(MotionEvent event) {
-        if (mKeyguardView != null) {
-            mKeyguardView.onExternalMotionEvent(event);
-        }
-    }
-
-    public void launchCamera() {
-        if (mKeyguardView != null) {
-            mKeyguardView.launchCamera();
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java b/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
index 9930e72..7128211 100644
--- a/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
+++ b/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
@@ -22,12 +22,21 @@
 
 public class MultiUserAvatarCache {
 
+    private static MultiUserAvatarCache sInstance;
+
     private final HashMap<Integer, Drawable> mCache;
 
-    public MultiUserAvatarCache() {
+    private MultiUserAvatarCache() {
         mCache = new HashMap<Integer, Drawable>();
     }
 
+    public static MultiUserAvatarCache getInstance() {
+        if (sInstance == null) {
+            sInstance = new MultiUserAvatarCache();
+        }
+        return sInstance;
+    }
+
     public void clear(int userId) {
         mCache.remove(userId);
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index d233ee9..b42a085 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -56,7 +56,7 @@
 public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
     private static final int WARP_SNAP_DURATION = 160;
     private static final String TAG = "WidgetPagedView";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_WARP = false;
     protected static final int INVALID_PAGE = -1;
     private static final int WARP_PEEK_ANIMATION_DURATION = 150;
diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
index 3d515ce..ab9286b 100644
--- a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
+++ b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
@@ -45,7 +45,7 @@
  */
 public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
     private static final String TAG = "SlidingChallengeLayout";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = KeyguardConstants.DEBUG;
 
     // The drag handle is measured in dp above & below the top edge of the
     // challenge view; these parameters change based on whether the challenge
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
new file mode 100644
index 0000000..1f23785
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 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.keyguard;
+
+/**
+ * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
+ * various things.
+ */
+public interface ViewMediatorCallback {
+    /**
+     * Reports user activity and requests that the screen stay on.
+     */
+    void userActivity();
+
+    /**
+     * Reports user activity and requests that the screen stay on for at least
+     * the specified amount of time.
+     * @param millis The amount of time in millis.  This value is currently ignored.
+     */
+    void userActivity(long millis);
+
+    /**
+     * Report that the keyguard is done.
+     * @param authenticated Whether the user securely got past the keyguard.
+     *   the only reason for this to be false is if the keyguard was instructed
+     *   to appear temporarily to verify the user is supposed to get past the
+     *   keyguard, and the user fails to do so.
+     */
+    void keyguardDone(boolean authenticated);
+
+    /**
+     * Report that the keyguard is done drawing.
+     */
+    void keyguardDoneDrawing();
+
+    /**
+     * Tell ViewMediator that the current view needs IME input
+     * @param needsInput
+     */
+    void setNeedsInput(boolean needsInput);
+
+    /**
+     * Tell view mediator that the keyguard view's desired user activity timeout
+     * has changed and needs to be reapplied to the window.
+     */
+    void onUserActivityTimeoutChanged();
+
+    /**
+     * Report that the keyguard is dismissable, pending the next keyguardDone call.
+     */
+    void keyguardDonePending();
+
+    /**
+     * Report when keyguard is actually gone
+     */
+    void keyguardGone();
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java b/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
index 55750cc..20af2f1 100644
--- a/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
+++ b/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
@@ -80,7 +80,7 @@
         public void onScreenOn();
         public void onScreenOff();
         public boolean onTouchEvent(MotionEvent ev, int width, int height);
-        public void onSetHidden(boolean hidden);
+        public void onSetOccluded(boolean hidden);
     }
 
     public interface SessionTypeAdapter {
@@ -256,11 +256,11 @@
         }
 
         @Override
-        public void onSetHidden(boolean hidden) {
+        public void onSetOccluded(boolean hidden) {
             synchronized (KeyguardAnalytics.this) {
                 if (hidden != mHidden) {
                     if (DEBUG) {
-                        Log.d(TAG, "onSetHidden(" + hidden + ")");
+                        Log.d(TAG, "onSetOccluded(" + hidden + ")");
                     }
                     mHidden = hidden;
                     if (hidden) {
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 1a871f8..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -69,8 +69,8 @@
     <item msgid="2762241247228983754">"Farve"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Stående"</item>
-    <item msgid="3199660090246166812">"Liggende"</item>
+    <item msgid="4061931020926489228">"Portræt"</item>
+    <item msgid="3199660090246166812">"Landskab"</item>
   </string-array>
   <string-array name="page_options_labels">
     <item msgid="7421377442011699994">"Alle"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index e299508..5d4fe94 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -69,7 +69,7 @@
     <item msgid="2762241247228983754">"Barvno"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Pokončno"</item>
+    <item msgid="4061931020926489228">"Navpično"</item>
     <item msgid="3199660090246166812">"Ležeče"</item>
   </string-array>
   <string-array name="page_options_labels">
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index a84e9b3..55c8687 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -31,7 +31,7 @@
     <string name="install_for_print_preview" msgid="6366303997385509332">"Sakinisha kitazamaji cha PDF kwa onyesho la kuchungulia"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"Programu ya kuchapisha imeacha kufanya kazi"</string>
     <string name="page_count_unknown" msgid="6058852665954511124">"Kurasa"</string>
-    <string name="generating_print_job" msgid="3119608742651698916">"Inaleta kazi ya kuchapisha"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"Inazanzisha kazi ya kuchapisha"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"Hifadhi kama PDF"</string>
     <string name="all_printers" msgid="5018829726861876202">"Printa zote..."</string>
     <string name="print_dialog" msgid="32628687461331979">"Chapisha mazungumzo"</string>
@@ -63,7 +63,7 @@
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"haijulikani"</string>
     <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - haipatikani"</string>
-    <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
+    <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuunda kazi ya kuchapisha"</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
     <item msgid="2762241247228983754">"Rangi"</item>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 19286c8..e1c17cb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -87,6 +87,8 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
+    <uses-permission android:name="android.permission.RENDER_STATS" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 59c3ccf..99f36f9 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,8 +17,8 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
-    <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
-    <string name="bugreport_finished_text" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Správa o chybách sa zaznamenala"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Dotykom môžete zdieľať správu o chybách"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
 </resources>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index f8f064a..69c6159 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     src/com/android/systemui/EventLogTags.logtags
 
+LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
@@ -14,6 +15,11 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
+LOCAL_RESOURCE_DIR := \
+    frameworks/base/packages/Keyguard/res \
+    $(LOCAL_PATH)/res
+LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard
+
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3424eed..d371d70 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -89,11 +89,20 @@
 
     <!-- Keyguard -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+    <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+    <uses-permission android:name="android.permission.TRUST_LISTENER" />
 
     <!-- Wifi Display -->
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
 
     <application
+        android:name=".SystemUIApplication"
         android:persistent="true"
         android:allowClearUserData="false"
         android:allowBackup="false"
@@ -101,7 +110,11 @@
         android:label="@string/app_label"
         android:icon="@*android:drawable/platlogo"
         android:process="com.android.systemui"
-        android:supportsRtl="true">
+        android:supportsRtl="true"
+        android:theme="@style/systemui_theme">
+        <!-- Keep theme in sync with SystemUIApplication.onCreate().
+             Setting the theme on the application does not affect views inflated by services.
+             The application theme is set again from onCreate to take effect for those views. -->
 
         <!-- Broadcast receiver that gets the broadcast at boot time and starts
              up everything else.
@@ -258,6 +271,10 @@
             </intent-filter>
         </service>
 
+        <service
+            android:name=".keyguard.KeyguardService"
+            android:exported="true" />
+
         <activity android:name=".Somnambulator"
             android:label="@string/start_dreams"
             android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 48d9722..da37803 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -6,7 +6,7 @@
   public void setGlowAlpha(float);
   public void setGlowScale(float);
 }
--keep class com.android.systemui.recents.views.TaskIconView {
+-keep class com.android.systemui.recents.views.TaskInfoView {
 	public void setCircularClipRadius(float);
 	public float getCircularClipRadius();
 }
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-hdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 46d2a16..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 704b4ec..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index d56efb5..0000000
--- a/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-mdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-xhdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off.png
rename to packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_off_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on_alpha.png
similarity index 100%
rename from packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on.png
rename to packages/SystemUI/res/drawable-xxhdpi/ic_qs_brightness_auto_on_alpha.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml b/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
index 85f1ea2..3a47261 100644
--- a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
+++ b/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
@@ -15,6 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"  android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
-    <item                               android:drawable="@*android:drawable/list_selector_disabled_holo_dark" />
+    <item android:state_pressed="true"
+          android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
 </selector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml
new file mode 100644
index 0000000..b7fe5ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_off.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_qs_brightness_auto_off_alpha"
+    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml
new file mode 100644
index 0000000..e17b533
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_brightness_auto_on.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_qs_brightness_auto_on_alpha"
+    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
deleted file mode 100644
index 0947c6f..0000000
--- a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the combined status bar / notification panel window. -->
-<com.android.systemui.statusbar.phone.StatusBarWindowView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:focusable="true"
-    android:descendantFocusability="afterDescendants"
-    android:fitsSystemWindows="true"
-    >
-
-    <include layout="@layout/status_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/status_bar_height"
-        />
-
-
-    <com.android.systemui.statusbar.phone.PanelHolder
-        android:id="@+id/panel_holder"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@*android:dimen/status_bar_height"
-        >
-        <include layout="@layout/status_bar_expanded"
-            android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start|top"
-            />
-        <include layout="@layout/quick_settings"
-            android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="end|top"
-            />
-    </com.android.systemui.statusbar.phone.PanelHolder>
-</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 5488a87..a6fb443 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -169,6 +169,7 @@
                 android:scaleType="center"
                 android:visibility="gone"
                 android:contentDescription="@string/accessibility_camera_button"
+                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
                 />
         </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index a6f4e9b..b7df51d 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -13,27 +13,25 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout 
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     style="@style/BrightnessDialogContainer">
 
     <ImageView
         android:id="@+id/brightness_icon"
-	    android:layout_width="wrap_content"
-	    android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:paddingEnd="10dp"
+        android:layout_marginEnd="8dp"
         android:src="@drawable/ic_qs_brightness_auto_off"
-        />
+        android:contentDescription="@null" />
+
     <com.android.systemui.settings.ToggleSlider
         android:id="@+id/brightness_slider"
         android:layout_width="0dp"
         android:layout_height="40dp"
-        android:layout_weight="1"
-        android:layout_marginEnd="2dp"
         android:layout_gravity="center_vertical"
-        systemui:text="@string/status_bar_settings_auto_brightness_label"
-        />
+        android:layout_weight="1"
+        systemui:text="@string/status_bar_settings_auto_brightness_label" />
+
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 8297878..7f64032 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -21,6 +21,21 @@
         android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
+    <com.android.systemui.recents.views.TaskInfoView
+    	android:id="@+id/task_view_info_pane"
+    	android:layout_width="match_parent"
+    	android:layout_height="match_parent"
+    	android:visibility="invisible"
+        android:background="#e6444444">
+        <Button
+        	android:id="@+id/task_view_app_info_button"
+        	android:layout_width="match_parent"
+        	android:layout_height="wrap_content"
+        	android:layout_marginStart="20dp"
+        	android:layout_marginEnd="20dp"
+    		android:layout_gravity="top|center_horizontal"
+        	android:text="@string/recents_app_info_button_label" />
+    </com.android.systemui.recents.views.TaskInfoView>
     <com.android.systemui.recents.views.TaskBarView
         android:id="@+id/task_view_bar"
         android:layout_width="match_parent"
@@ -31,15 +46,15 @@
             android:id="@+id/application_icon"
             android:layout_width="@dimen/recents_task_view_application_icon_size"
             android:layout_height="@dimen/recents_task_view_application_icon_size"
-            android:layout_gravity="center_vertical|left"
+            android:layout_gravity="center_vertical|start"
             android:padding="8dp" />
         <TextView
             android:id="@+id/activity_description"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|left"
-            android:layout_marginLeft="@dimen/recents_task_view_application_icon_size"
-            android:layout_marginRight="@dimen/recents_task_view_activity_icon_size"
+            android:layout_marginStart="@dimen/recents_task_view_application_icon_size"
+            android:layout_marginEnd="@dimen/recents_task_view_activity_icon_size"
             android:textSize="24sp"
             android:textColor="#ffffffff"
             android:text="@string/recents_empty_message"
@@ -52,7 +67,7 @@
             android:id="@+id/activity_icon"
             android:layout_width="@dimen/recents_task_view_activity_icon_size"
             android:layout_height="@dimen/recents_task_view_activity_icon_size"
-            android:layout_gravity="center_vertical|right"
+            android:layout_gravity="center_vertical|end"
             android:padding="12dp"
             android:visibility="invisible" />
     </com.android.systemui.recents.views.TaskBarView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index ea6be1b..1b35537 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -27,7 +27,6 @@
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
-    android:fitsSystemWindows="true"
     >
 
     <ImageView
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index a7ec064..8f4417e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -36,6 +36,14 @@
         android:layout_gravity="bottom"
         />
 
+    <ViewStub android:id="@+id/keyguard_flip_stub"
+        android:layout="@layout/status_bar_flip_button"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_gravity="right|top"
+        android:layout_marginTop="@*android:dimen/status_bar_height"
+        android:visibility="gone" />
+
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -49,6 +57,10 @@
             android:layout_height="@dimen/notification_panel_header_height"
             />
 
+        <include
+            layout="@layout/keyguard_status_view"
+            android:visibility="gone" />
+
         <TextView
             android:id="@+id/emergency_calls_only"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 9aa7cfd..56523db 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -81,29 +81,10 @@
         android:src="@drawable/ic_notify_clear"
         android:background="@drawable/ic_notify_button_bg"
         android:contentDescription="@string/accessibility_clear_all"
-        />     
+        />
 
-    <FrameLayout android:id="@+id/settings_button_holder"
+    <include layout="@layout/status_bar_flip_button"
         android:layout_width="50dp"
         android:layout_height="50dp"
-        android:layout_marginStart="12dp"
-        >
-        <ImageView android:id="@+id/settings_button"
-            android:layout_width="50dp"
-            android:layout_height="50dp"
-            android:scaleType="center"
-            android:src="@drawable/ic_notify_settings"
-            android:background="@drawable/ic_notify_button_bg"
-            android:contentDescription="@string/accessibility_desc_quick_settings"
-            />
-        <ImageView android:id="@+id/notification_button"
-            android:layout_width="50dp"
-            android:layout_height="50dp"
-            android:scaleType="center"
-            android:src="@drawable/ic_notifications"
-            android:background="@drawable/ic_notify_button_bg"
-            android:visibility="gone"
-            android:contentDescription="@string/accessibility_notifications_button"
-            />
-    </FrameLayout>
+        android:layout_marginStart="12dp" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
new file mode 100644
index 0000000..db672ea
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/settings_button_holder"
+        android:layout_width="50dp"
+        android:layout_height="50dp">
+    <ImageView android:id="@+id/settings_button"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:scaleType="center"
+        android:src="@drawable/ic_notify_settings"
+        android:background="@drawable/ic_notify_button_bg"
+        android:contentDescription="@string/accessibility_desc_quick_settings" />
+    <ImageView android:id="@+id/notification_button"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:scaleType="center"
+        android:src="@drawable/ic_notifications"
+        android:background="@drawable/ic_notify_button_bg"
+        android:visibility="gone"
+        android:contentDescription="@string/accessibility_notifications_button" />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
new file mode 100644
index 0000000..79b03ce
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -0,0 +1,51 @@
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    >
+    <com.android.systemui.statusbar.LatestItemView
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:layout_marginTop="@dimen/notification_divider_height"
+        android:focusable="true"
+        android:clickable="true"
+        android:background="@*android:drawable/notification_quantum_bg_dim"
+        >
+        <TextView
+            android:id="@+id/more_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:gravity="center_horizontal"
+            android:textColor="@color/keyguard_overflow_content_color"
+            android:textAllCaps="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            />
+        <com.android.systemui.statusbar.NotificationOverflowIconsView
+            android:id="@+id/overflow_icons_view"
+            android:layout_gravity="end|center_vertical"
+            android:gravity="end"
+            android:paddingLeft="8dp"
+            android:paddingRight="8dp"
+            android:layout_width="120dp"
+            android:layout_height="wrap_content"
+            />
+    </com.android.systemui.statusbar.LatestItemView>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index e74e568..d61d8b9 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -32,6 +32,7 @@
         android:layout_marginTop="@dimen/notification_divider_height"
         android:focusable="true"
         android:clickable="true"
+        android:background="@*android:drawable/notification_quantum_bg"
         >
 
         <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 2b56618..9176d24 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -20,32 +20,29 @@
 <!-- This is the combined status bar / notification panel window. -->
 <com.android.systemui.statusbar.phone.StatusBarWindowView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:focusable="true"
-    android:descendantFocusability="afterDescendants"
-    android:fitsSystemWindows="true"
-    android:background="@android:color/transparent"
-    >
+    android:descendantFocusability="afterDescendants">
 
     <include layout="@layout/status_bar"
         android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/status_bar_height"
-        />
+        android:layout_height="@*android:dimen/status_bar_height" />
 
     <com.android.systemui.statusbar.phone.PanelHolder
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        >
+        android:layout_marginTop="@dimen/panel_holder_padding_top"
+        android:layout_marginBottom="@*android:dimen/navigation_bar_height">
         <include layout="@layout/status_bar_expanded"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            />
+            android:layout_width="@dimen/notification_panel_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|top" />
         <ViewStub android:id="@+id/quick_settings_stub"
             android:layout="@layout/quick_settings"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            />
+            android:layout_width="@dimen/notification_panel_width"
+            android:layout_height="match_parent" />
     </com.android.systemui.statusbar.phone.PanelHolder>
 
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml
new file mode 100644
index 0000000..bc56cf6
--- /dev/null
+++ b/packages/SystemUI/res/layout/user_switcher_host.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- FrameLayout -->
+<com.android.systemui.settings.UserSwitcherHostView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#dd000000">
+    <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@*android:dimen/volume_panel_top"
+            android:background="@*android:drawable/dialog_full_holo_dark">
+        <ListView android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                tools:listitem="@layout/user_switcher_item"/>
+    </FrameLayout>
+</com.android.systemui.settings.UserSwitcherHostView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/user_switcher_item.xml b/packages/SystemUI/res/layout/user_switcher_item.xml
new file mode 100644
index 0000000..43a85e7
--- /dev/null
+++ b/packages/SystemUI/res/layout/user_switcher_item.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 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"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:orientation="horizontal"
+        tools:context=".settings.UserSwitcherDialog">
+    <ImageView
+            android:layout_width="64dp"
+            android:layout_height="match_parent"
+            android:id="@+id/user_picture"
+            tools:src="@drawable/dessert_zombiegingerbread"/>
+    <TextView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:id="@+id/user_name"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:padding="8dp"
+            android:gravity="center_vertical"
+            tools:text="Hiroshi Lockheimer"
+            />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index b77f1e0c..440ead6 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -30,5 +30,5 @@
     <integer name="quick_settings_user_time_settings_tile_span">1</integer>
 
     <!-- Enable the "flip settings" panel -->
-    <bool name="config_hasFlipSettingsPanel">false</bool>
+    <bool name="config_hasFlipSettingsPanel">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 45f6af3..b4fafec 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -24,8 +24,8 @@
     <dimen name="notification_panel_margin_left">16dp</dimen>
 
     <!-- Gravity for the notification & quick settings panels -->
-    <!-- 0x800033 = start|top ; 0x800035 = end|top -->
-    <integer name="notification_panel_layout_gravity">0x800033</integer>
+    <!-- 0x31 = top|center_horizontal ; 0x800035 = end|top -->
+    <integer name="notification_panel_layout_gravity">0x31</integer>
     <integer name="settings_panel_layout_gravity">0x800035</integer>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
@@ -41,9 +41,8 @@
     <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
     <dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
 
-    <!-- On tablet-sized devices, we allocate the rightmost third(ish) of the draggable status bar
-         to quick settings. -->
-    <item type="dimen" name="settings_panel_dragzone_fraction">35%</item>
+    <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
+    <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
 
     <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
     <item type="dimen" name="notification_panel_min_height_frac">40%</item>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5cf0453..59e8360 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -31,7 +31,8 @@
     <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
     <drawable name="notification_header_bg">#FF000000</drawable>
-    <color name="notification_panel_scrim_color">#B0000000</color>
+    <color name="notification_panel_scrim_color">#A0000000</color>
+    <color name="notification_panel_scrim_color_keyguard">#80000000</color>
     <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
@@ -45,4 +46,7 @@
 
     <!-- Tint color for active Quick Settings icons. -->
     <color name="ic_qs_on">#ffffffff</color>
+
+    <!-- Tint color for the content on the notification overflow card. -->
+    <color name="keyguard_overflow_content_color">#ff666666</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 672c1d0..478c541 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -114,5 +114,11 @@
     <integer name="recents_filter_animate_new_views_min_duration">125</integer>
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_animate_task_bar_enter_duration">200</integer>
+    <!-- The animation duration for animating in the info pane. -->
+    <integer name="recents_animate_task_view_info_pane_duration">150</integer>
+
+    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+     card. -->
+    <integer name="keyguard_max_notification_count">4</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2c8f9a1..94d3541 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -167,6 +167,9 @@
     <!-- Extra space above the clock in the panel -->
     <dimen name="notification_panel_header_padding_top">0dp</dimen>
 
+    <!-- Extra space above the panel holder -->
+    <dimen name="panel_holder_padding_top">0dp</dimen>
+
     <!-- Layout parameters for the notification panel -->
     <dimen name="notification_panel_margin_bottom">0dp</dimen>
     <dimen name="notification_panel_margin_left">0dp</dimen>
@@ -236,6 +239,9 @@
     <!-- The size of the activity icon in the recents task view. -->
     <dimen name="recents_task_view_activity_icon_size">60dp</dimen>
 
+    <!-- The amount of space a user has to scroll to dismiss any info panes. -->
+    <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
+
     <!-- Used to calculate the translation animation duration, the expected amount of movement 
          in dps over one second of time. -->
     <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
@@ -257,4 +263,7 @@
 
     <!-- Width of the zen mode interstitial dialog. -->
     <dimen name="zen_mode_dialog_width">320dp</dimen>
+
+    <!-- Camera affordance drag distance -->
+    <dimen name="camera_drag_distance">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ad10545..73e5e19 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -509,6 +509,8 @@
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">RECENTS</string>
+    <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
+    <string name="recents_app_info_button_label">Application Info</string>
 
 
     <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
@@ -534,4 +536,9 @@
     </plurals>
     <!-- Zen mode: Summary notification content text. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_notification_text">Touch to show</string>
+
+    <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=12] -->
+    <plurals name="keyguard_more_overflow_text">
+        <item quantity="other">%d more</item>
+    </plurals>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 76cadd7..8ab646d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -137,10 +137,9 @@
     <style name="BaseBrightnessDialogContainer">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginLeft">8dp</item>
-        <item name="android:layout_marginRight">8dp</item>
         <item name="android:padding">16dp</item>
     </style>
+
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
 
     <style name="Animation" />
@@ -169,5 +168,7 @@
         <!-- Note: must be dp to fit in status bar -->
         <item name="android:textSize">14dp</item>
     </style>
-    
+
+    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
new file mode 100644
index 0000000..0f55683
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 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.systemui;
+
+import android.app.Application;
+import android.content.res.Configuration;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Application class for SystemUI.
+ */
+public class SystemUIApplication extends Application {
+
+    private static final String TAG = "SystemUIService";
+    private static final boolean DEBUG = false;
+
+    /**
+     * The classes of the stuff to start.
+     */
+    private final Class<?>[] SERVICES = new Class[] {
+            com.android.systemui.keyguard.KeyguardViewMediator.class,
+            com.android.systemui.recent.Recents.class,
+            com.android.systemui.statusbar.SystemBars.class,
+            com.android.systemui.usb.StorageNotification.class,
+            com.android.systemui.power.PowerUI.class,
+            com.android.systemui.media.RingtonePlayer.class,
+            com.android.systemui.settings.SettingsUI.class,
+    };
+
+    /**
+     * Hold a reference on the stuff we start.
+     */
+    private final SystemUI[] mServices = new SystemUI[SERVICES.length];
+    private boolean mServicesStarted;
+    private final Map<Class<?>, Object> mComponents = new HashMap<Class<?>, Object>();
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        // Set the application theme that is inherited by all services. Note that setting the
+        // application theme in the manifest does only work for activities. Keep this in sync with
+        // the theme set there.
+        setTheme(R.style.systemui_theme);
+    }
+
+    /**
+     * Makes sure that all the SystemUI services are running. If they are already running, this is a
+     * no-op. This is needed to conditinally start all the services, as we only need to have it in
+     * the main process.
+     *
+     * <p>This method must only be called from the main thread.</p>
+     */
+    public void startServicesIfNeeded() {
+        if (mServicesStarted) {
+            return;
+        }
+        final int N = SERVICES.length;
+        for (int i=0; i<N; i++) {
+            Class<?> cl = SERVICES[i];
+            if (DEBUG) Log.d(TAG, "loading: " + cl);
+            try {
+                mServices[i] = (SystemUI)cl.newInstance();
+            } catch (IllegalAccessException ex) {
+                throw new RuntimeException(ex);
+            } catch (InstantiationException ex) {
+                throw new RuntimeException(ex);
+            }
+            mServices[i].mContext = this;
+            mServices[i].mComponents = mComponents;
+            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
+            mServices[i].start();
+        }
+        mServicesStarted = true;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (mServicesStarted) {
+            int len = mServices.length;
+            for (int i = 0; i < len; i++) {
+                mServices[i].onConfigurationChanged(newConfig);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getComponent(Class<T> interfaceType) {
+        return (T) mComponents.get(interfaceType);
+    }
+
+    public SystemUI[] getServices() {
+        return mServices;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index ca5f7d1..05e5f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -18,80 +18,35 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.os.IBinder;
-import android.util.Log;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.HashMap;
 
 public class SystemUIService extends Service {
-    private static final String TAG = "SystemUIService";
-
-    /**
-     * The classes of the stuff to start.
-     */
-    private final Class<?>[] SERVICES = new Class[] {
-            com.android.systemui.recent.Recents.class,
-            com.android.systemui.statusbar.SystemBars.class,
-            com.android.systemui.usb.StorageNotification.class,
-            com.android.systemui.power.PowerUI.class,
-            com.android.systemui.media.RingtonePlayer.class,
-            com.android.systemui.settings.SettingsUI.class,
-        };
-
-    /**
-     * Hold a reference on the stuff we start.
-     */
-    private final SystemUI[] mServices = new SystemUI[SERVICES.length];
 
     @Override
     public void onCreate() {
-        HashMap<Class<?>, Object> components = new HashMap<Class<?>, Object>();
-        final int N = SERVICES.length;
-        for (int i=0; i<N; i++) {
-            Class<?> cl = SERVICES[i];
-            Log.d(TAG, "loading: " + cl);
-            try {
-                mServices[i] = (SystemUI)cl.newInstance();
-            } catch (IllegalAccessException ex) {
-                throw new RuntimeException(ex);
-            } catch (InstantiationException ex) {
-                throw new RuntimeException(ex);
-            }
-            mServices[i].mContext = this;
-            mServices[i].mComponents = components;
-            Log.d(TAG, "running: " + mServices[i]);
-            mServices[i].start();
-        }
+        super.onCreate();
+        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
     }
 
     @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        for (SystemUI ui: mServices) {
-            ui.onConfigurationChanged(newConfig);
-        }
-    }
-
-    /**
-     * Nobody binds to us.
-     */
-    @Override
     public IBinder onBind(Intent intent) {
         return null;
     }
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
         if (args == null || args.length == 0) {
-            for (SystemUI ui: mServices) {
+            for (SystemUI ui: services) {
                 pw.println("dumping service: " + ui.getClass().getName());
                 ui.dump(fd, pw, args);
             }
         } else {
             String svc = args[0];
-            for (SystemUI ui: mServices) {
+            for (SystemUI ui: services) {
                 String name = ui.getClass().getName();
                 if (name.endsWith(svc)) {
                     ui.dump(fd, pw, args);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
similarity index 65%
rename from packages/Keyguard/src/com/android/keyguard/KeyguardService.java
rename to packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 36b2446..41c0e78 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -11,18 +11,13 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.keyguard;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+package com.android.systemui.keyguard;
 
 import android.app.Service;
 import android.content.Intent;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -30,23 +25,25 @@
 import android.util.Log;
 import android.view.MotionEvent;
 
-import com.android.internal.policy.IKeyguardService;
 import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardServiceConstants;
 import com.android.internal.policy.IKeyguardShowCallback;
-import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.SystemUIApplication;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 public class KeyguardService extends Service {
     static final String TAG = "KeyguardService";
     static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
+
     private KeyguardViewMediator mKeyguardViewMediator;
 
     @Override
     public void onCreate() {
-        if (mKeyguardViewMediator == null) {
-            mKeyguardViewMediator = new KeyguardViewMediator(
-                    KeyguardService.this, new LockPatternUtils(KeyguardService.this));
-        }
-        Log.v(TAG, "onCreate()");
+        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
+        mKeyguardViewMediator =
+                ((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
     }
 
     @Override
@@ -54,11 +51,6 @@
         return mBinder;
     }
 
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        // TODO
-    }
-
     void checkPermission() {
         if (getBaseContext().checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
             Log.w(TAG, "Caller needs permission '" + PERMISSION + "' to call " + Debug.getCaller());
@@ -68,84 +60,148 @@
     }
 
     private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
+
+        private boolean mIsOccluded;
+
+        @Override
         public boolean isShowing() {
             return mKeyguardViewMediator.isShowing();
         }
+
+        @Override
         public boolean isSecure() {
             return mKeyguardViewMediator.isSecure();
         }
-        public boolean isShowingAndNotHidden() {
-            return mKeyguardViewMediator.isShowingAndNotHidden();
+
+        @Override
+        public boolean isShowingAndNotOccluded() {
+            return mKeyguardViewMediator.isShowingAndNotOccluded();
         }
+
+        @Override
         public boolean isInputRestricted() {
             return mKeyguardViewMediator.isInputRestricted();
         }
+
+        @Override
         public void verifyUnlock(IKeyguardExitCallback callback) {
+            checkPermission();
             mKeyguardViewMediator.verifyUnlock(callback);
         }
+
+        @Override
         public void keyguardDone(boolean authenticated, boolean wakeup) {
             checkPermission();
             mKeyguardViewMediator.keyguardDone(authenticated, wakeup);
         }
-        public void setHidden(boolean isHidden) {
+
+        @Override
+        public int setOccluded(boolean isOccluded) {
             checkPermission();
-            mKeyguardViewMediator.setHidden(isHidden);
+            synchronized (this) {
+                int result;
+                if (isOccluded && mKeyguardViewMediator.isShowing()
+                        && !mIsOccluded) {
+                    result = IKeyguardServiceConstants
+                            .KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS;
+                } else if (!isOccluded && mKeyguardViewMediator.isShowing()
+                        && mIsOccluded) {
+                    result = IKeyguardServiceConstants
+                            .KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS;
+                } else {
+                    result = IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE;
+                }
+                if (mIsOccluded != isOccluded) {
+                    mKeyguardViewMediator.setOccluded(isOccluded);
+
+                    // Cache the value so we always have a fresh view in whether Keyguard is occluded.
+                    // If we would just call mKeyguardViewMediator.isOccluded(), this might be stale
+                    // because that value gets updated in another thread.
+                    mIsOccluded = isOccluded;
+                }
+                return result;
+            }
         }
+
+        @Override
         public void dismiss() {
+            checkPermission();
             mKeyguardViewMediator.dismiss();
         }
+
+        @Override
         public void onDreamingStarted() {
             checkPermission();
             mKeyguardViewMediator.onDreamingStarted();
         }
+
+        @Override
         public void onDreamingStopped() {
             checkPermission();
             mKeyguardViewMediator.onDreamingStopped();
         }
+
+        @Override
         public void onScreenTurnedOff(int reason) {
             checkPermission();
             mKeyguardViewMediator.onScreenTurnedOff(reason);
         }
+
+        @Override
         public void onScreenTurnedOn(IKeyguardShowCallback callback) {
             checkPermission();
             mKeyguardViewMediator.onScreenTurnedOn(callback);
         }
+
+        @Override
         public void setKeyguardEnabled(boolean enabled) {
             checkPermission();
             mKeyguardViewMediator.setKeyguardEnabled(enabled);
         }
+
+        @Override
         public boolean isDismissable() {
             return mKeyguardViewMediator.isDismissable();
         }
+
+        @Override
         public void onSystemReady() {
             checkPermission();
             mKeyguardViewMediator.onSystemReady();
         }
+
+        @Override
         public void doKeyguardTimeout(Bundle options) {
             checkPermission();
             mKeyguardViewMediator.doKeyguardTimeout(options);
         }
+
+        @Override
         public void setCurrentUser(int userId) {
             checkPermission();
             mKeyguardViewMediator.setCurrentUser(userId);
         }
+
+        @Override
         public void showAssistant() {
             checkPermission();
-            mKeyguardViewMediator.showAssistant();
         }
+
+        @Override
         public void dispatch(MotionEvent event) {
             checkPermission();
-            mKeyguardViewMediator.dispatch(event);
         }
+
+        @Override
         public void launchCamera() {
             checkPermission();
-            mKeyguardViewMediator.launchCamera();
         }
+
+        @Override
         public void onBootCompleted() {
             checkPermission();
             mKeyguardViewMediator.onBootCompleted();
         }
     };
-
 }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
similarity index 85%
rename from packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
rename to packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 354d13f..bb39d36 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -11,15 +11,10 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.keyguard;
-
-import com.android.internal.policy.IKeyguardExitCallback;
-import com.android.internal.policy.IKeyguardShowCallback;
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapter;
+package com.android.systemui.keyguard;
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
@@ -50,17 +45,31 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.view.MotionEvent;
+import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.analytics.Session;
+import com.android.keyguard.KeyguardDisplayManager;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.MultiUserAvatarCache;
+import com.android.keyguard.ViewMediatorCallback;
 import com.android.keyguard.analytics.KeyguardAnalytics;
+import com.android.keyguard.analytics.Session;
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 
 import java.io.File;
 
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapter;
+
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -95,15 +104,15 @@
  * false, this will override all other conditions for turning on the keyguard.
  *
  * Threading and synchronization:
- * This class is created by the initialization routine of the {@link WindowManagerPolicy},
+ * This class is created by the initialization routine of the {@link android.view.WindowManagerPolicy},
  * and runs on its thread.  The keyguard UI is created from that thread in the
  * constructor of this class.  The apis may be called from other threads, including the
  * {@link com.android.server.input.InputManagerService}'s and {@link android.view.WindowManager}'s.
  * Therefore, methods on this class are synchronized, and any action that is pointed
- * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI
+ * directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI
  * thread of the keyguard.
  */
-public class KeyguardViewMediator {
+public class KeyguardViewMediator extends SystemUI {
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     final static boolean DEBUG = false;
     private static final boolean ENABLE_ANALYTICS = Build.IS_DEBUGGABLE;
@@ -124,17 +133,14 @@
     private static final int KEYGUARD_DONE = 9;
     private static final int KEYGUARD_DONE_DRAWING = 10;
     private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
-    private static final int SET_HIDDEN = 12;
+    private static final int SET_OCCLUDED = 12;
     private static final int KEYGUARD_TIMEOUT = 13;
-    private static final int SHOW_ASSISTANT = 14;
-    private static final int DISPATCH_EVENT = 15;
-    private static final int LAUNCH_CAMERA = 16;
     private static final int DISMISS = 17;
 
     /**
      * The default amount of time we stay awake (used for all key input)
      */
-    protected static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
+    public static final int AWAKE_INTERVAL_DEFAULT_MS = 10000;
 
     /**
      * How long to wait after the screen turns off due to timeout before
@@ -158,13 +164,13 @@
 
     /**
      * Allow the user to expand the status bar when a SECURE keyguard is engaged
-     * and {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS} is set
+     * and {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS} is set
      * (private notifications will be masked).
      */
     private static final boolean ENABLE_SECURE_STATUS_BAR_EXPAND = true;
 
     /**
-     * Default value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
+     * Default value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
      */
     private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
 
@@ -176,7 +182,6 @@
     /** The stream type that the lock sounds are tied to. */
     private int mMasterStreamType;
 
-    private Context mContext;
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
     private StatusBarManager mStatusBarManager;
@@ -204,9 +209,9 @@
      */
     private PowerManager.WakeLock mShowKeyguardWakeLock;
 
-    private KeyguardViewManager mKeyguardViewManager;
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
-    private final KeyguardAnalytics mKeyguardAnalytics;
+    private KeyguardAnalytics mKeyguardAnalytics;
 
     // these are protected by synchronized (this)
 
@@ -227,7 +232,7 @@
     private boolean mShowing;
 
     // true if the keyguard is hidden by another window
-    private boolean mHidden = false;
+    private boolean mOccluded = false;
 
     /**
      * Helps remember whether the screen has turned on since the last time
@@ -272,79 +277,20 @@
     private int mLockSoundStreamId;
 
     /**
-     * Tracks value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
+     * Tracks value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
      */
     private boolean mAllowNotificationsWhenSecure;
 
     /**
      * The volume applied to the lock/unlock sounds.
      */
-    private final float mLockSoundVolume;
+    private float mLockSoundVolume;
 
     /**
      * For managing external displays
      */
     private KeyguardDisplayManager mKeyguardDisplayManager;
 
-    /**
-     * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
-     */
-    private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
-
-    /**
-     * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
-     * various things.
-     */
-    public interface ViewMediatorCallback {
-        /**
-         * Reports user activity and requests that the screen stay on.
-         */
-        void userActivity();
-
-        /**
-         * Reports user activity and requests that the screen stay on for at least
-         * the specified amount of time.
-         * @param millis The amount of time in millis.  This value is currently ignored.
-         */
-        void userActivity(long millis);
-
-        /**
-         * Report that the keyguard is done.
-         * @param authenticated Whether the user securely got past the keyguard.
-         *   the only reason for this to be false is if the keyguard was instructed
-         *   to appear temporarily to verify the user is supposed to get past the
-         *   keyguard, and the user fails to do so.
-         */
-        void keyguardDone(boolean authenticated);
-
-        /**
-         * Report that the keyguard is done drawing.
-         */
-        void keyguardDoneDrawing();
-
-        /**
-         * Tell ViewMediator that the current view needs IME input
-         * @param needsInput
-         */
-        void setNeedsInput(boolean needsInput);
-
-        /**
-         * Tell view mediator that the keyguard view's desired user activity timeout
-         * has changed and needs to be reapplied to the window.
-         */
-        void onUserActivityTimeoutChanged();
-
-        /**
-         * Report that the keyguard is dismissable, pending the next keyguardDone call.
-         */
-        void keyguardDonePending();
-
-        /**
-         * Report when keyguard is actually gone
-         */
-        void keyguardGone();
-    }
-
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -354,7 +300,7 @@
             // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
             synchronized (KeyguardViewMediator.this) {
                 mSwitchingUser = true;
-                resetStateLocked(null);
+                resetStateLocked();
                 adjustStatusBarLocked();
                 // When we switch users we want to bring the new user to the biometric unlock even
                 // if the current user has gone to the backup.
@@ -370,16 +316,16 @@
         @Override
         public void onUserRemoved(int userId) {
             mLockPatternUtils.removeUser(userId);
-            sMultiUserAvatarCache.clear(userId);
+            MultiUserAvatarCache.getInstance().clear(userId);
         }
 
         @Override
         public void onUserInfoChanged(int userId) {
-            sMultiUserAvatarCache.clear(userId);
+            MultiUserAvatarCache.getInstance().clear(userId);
         }
 
         @Override
-        void onPhoneStateChanged(int phoneState) {
+        public void onPhoneStateChanged(int phoneState) {
             synchronized (KeyguardViewMediator.this) {
                 if (TelephonyManager.CALL_STATE_IDLE == phoneState  // call ending
                         && !mScreenOn                           // screen off
@@ -394,7 +340,7 @@
                     doKeyguardLocked(null);
                 }
             }
-        };
+        }
 
         @Override
         public void onClockVisibilityChanged() {
@@ -423,7 +369,7 @@
                                         + "device isn't provisioned yet.");
                                 doKeyguardLocked(null);
                             } else {
-                                resetStateLocked(null);
+                                resetStateLocked();
                             }
                         }
                     }
@@ -436,7 +382,7 @@
                                     + "showing; need to show keyguard so user can enter sim pin");
                             doKeyguardLocked(null);
                         } else {
-                            resetStateLocked(null);
+                            resetStateLocked();
                         }
                     }
                     break;
@@ -449,14 +395,14 @@
                         } else {
                             if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
                                   + "show permanently disabled message in lockscreen.");
-                            resetStateLocked(null);
+                            resetStateLocked();
                         }
                     }
                     break;
                 case READY:
                     synchronized (this) {
                         if (isShowing()) {
-                            resetStateLocked(null);
+                            resetStateLocked();
                         }
                     }
                     break;
@@ -466,6 +412,7 @@
     };
 
     ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
+
         public void userActivity() {
             KeyguardViewMediator.this.userActivity();
         }
@@ -484,12 +431,12 @@
 
         @Override
         public void setNeedsInput(boolean needsInput) {
-            mKeyguardViewManager.setNeedsInput(needsInput);
+            mStatusBarKeyguardViewManager.setNeedsInput(needsInput);
         }
 
         @Override
         public void onUserActivityTimeoutChanged() {
-            mKeyguardViewManager.updateUserActivityTimeout();
+            mStatusBarKeyguardViewManager.updateUserActivityTimeout();
         }
 
         @Override
@@ -513,40 +460,34 @@
         mPM.userActivity(SystemClock.uptimeMillis(), false);
     }
 
-    /**
-     * Construct a KeyguardViewMediator
-     * @param context
-     * @param lockPatternUtils optional mock interface for LockPatternUtils
-     */
-    public KeyguardViewMediator(Context context, LockPatternUtils lockPatternUtils) {
-        mContext = context;
-        mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+    private void setup() {
+        mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
         mShowKeyguardWakeLock.setReferenceCounted(false);
 
         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
 
-        mKeyguardDisplayManager = new KeyguardDisplayManager(context);
+        mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
 
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
-        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
 
-        mLockPatternUtils = lockPatternUtils != null
-                ? lockPatternUtils : new LockPatternUtils(mContext);
+        mLockPatternUtils = new LockPatternUtils(mContext);
         mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER);
 
         // Assume keyguard is showing (unless it's disabled) until we know for sure...
         mShowing = (mUpdateMonitor.isDeviceProvisioned() || mLockPatternUtils.isSecure())
                 && !mLockPatternUtils.isLockScreenDisabled();
 
-        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext,
+                mViewMediatorCallback, mLockPatternUtils);
         final ContentResolver cr = mContext.getContentResolver();
 
         if (ENABLE_ANALYTICS && !LockPatternUtils.isSafeModeEnabled() &&
                 Settings.Secure.getInt(cr, KEYGUARD_ANALYTICS_SETTING, 0) == 1) {
-            mKeyguardAnalytics = new KeyguardAnalytics(context, new SessionTypeAdapter() {
+            mKeyguardAnalytics = new KeyguardAnalytics(mContext, new SessionTypeAdapter() {
 
                 @Override
                 public int getSessionType() {
@@ -559,9 +500,6 @@
         } else {
             mKeyguardAnalytics = null;
         }
-        mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
-                mLockPatternUtils,
-                mKeyguardAnalytics != null ? mKeyguardAnalytics.getCallback() : null);
 
         mScreenOn = mPM.isScreenOn();
 
@@ -580,11 +518,17 @@
         if (soundPath == null || mUnlockSoundId == 0) {
             Log.w(TAG, "failed to load unlock sound from " + soundPath);
         }
-        int lockSoundDefaultAttenuation = context.getResources().getInteger(
+        int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lockSoundVolumeDb);
         mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
     }
 
+    @Override
+    public void start() {
+        setup();
+        putComponent(KeyguardViewMediator.class, this);
+    }
+
     /**
      * Let us know that the system is ready after startup.
      */
@@ -621,9 +565,9 @@
 
     /**
      * Called to let us know the screen was turned off.
-     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER},
+     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
+     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
      */
     public void onScreenTurnedOff(int why) {
         synchronized (this) {
@@ -651,7 +595,7 @@
                 }
             } else if (mShowing) {
                 notifyScreenOffLocked();
-                resetStateLocked(null);
+                resetStateLocked();
             } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
                 doKeyguardLaterLocked();
@@ -768,7 +712,7 @@
     }
 
     /**
-     * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
+     * Same semantics as {@link android.view.WindowManagerPolicy#enableKeyguard}; provide
      * a way for external stuff to override normal keyguard behavior.  For instance
      * the phone app disables the keyguard when it receives incoming calls.
      */
@@ -805,7 +749,7 @@
                         Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                     }
                     mExitSecureCallback = null;
-                    resetStateLocked(null);
+                    resetStateLocked();
                 } else {
                     showLocked(null);
 
@@ -873,36 +817,41 @@
         return mShowing;
     }
 
-    /**
-     * Is the keyguard currently showing and not being force hidden?
-     */
-    public boolean isShowingAndNotHidden() {
-        return mShowing && !mHidden;
+    public boolean isOccluded() {
+        return mOccluded;
     }
 
     /**
-     * Notify us when the keyguard is hidden by another window
+     * Is the keyguard currently showing and not being force hidden?
      */
-    public void setHidden(boolean isHidden) {
-        if (DEBUG) Log.d(TAG, "setHidden " + isHidden);
-        mUpdateMonitor.sendKeyguardVisibilityChanged(!isHidden);
-        mHandler.removeMessages(SET_HIDDEN);
-        Message msg = mHandler.obtainMessage(SET_HIDDEN, (isHidden ? 1 : 0), 0);
+    public boolean isShowingAndNotOccluded() {
+        return mShowing && !mOccluded;
+    }
+
+    /**
+     * Notify us when the keyguard is occluded by another window
+     */
+    public void setOccluded(boolean isOccluded) {
+        if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
+        mUpdateMonitor.sendKeyguardVisibilityChanged(!isOccluded);
+        mHandler.removeMessages(SET_OCCLUDED);
+        Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
         mHandler.sendMessage(msg);
     }
 
     /**
-     * Handles SET_HIDDEN message sent by setHidden()
+     * Handles SET_OCCLUDED message sent by setOccluded()
      */
-    private void handleSetHidden(boolean isHidden) {
+    private void handleSetOccluded(boolean isOccluded) {
         synchronized (KeyguardViewMediator.this) {
-            if (mHidden != isHidden) {
-                mHidden = isHidden;
+            if (mOccluded != isOccluded) {
+                mOccluded = isOccluded;
+                mStatusBarKeyguardViewManager.setOccluded(isOccluded);
                 updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
             if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) {
-                mKeyguardAnalytics.getCallback().onSetHidden(isHidden);
+                mKeyguardAnalytics.getCallback().onSetOccluded(isOccluded);
             }
         }
     }
@@ -954,7 +903,7 @@
                         ALLOW_NOTIFICATIONS_DEFAULT ? 1 : 0);
 
         // if the keyguard is already showing, don't bother
-        if (mKeyguardViewManager.isShowing()) {
+        if (mStatusBarKeyguardViewManager.isShowing()) {
             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
             return;
         }
@@ -996,8 +945,8 @@
      * Dismiss the keyguard through the security layers.
      */
     public void handleDismiss() {
-        if (mShowing && !mHidden) {
-            mKeyguardViewManager.dismiss();
+        if (mShowing && !mOccluded) {
+            mStatusBarKeyguardViewManager.dismiss();
         }
     }
 
@@ -1007,12 +956,11 @@
 
     /**
      * Send message to keyguard telling it to reset its state.
-     * @param options options about how to show the keyguard
-     * @see #handleReset()
+     * @see #handleReset
      */
-    private void resetStateLocked(Bundle options) {
+    private void resetStateLocked() {
         if (DEBUG) Log.e(TAG, "resetStateLocked");
-        Message msg = mHandler.obtainMessage(RESET, options);
+        Message msg = mHandler.obtainMessage(RESET);
         mHandler.sendMessage(msg);
     }
 
@@ -1038,7 +986,7 @@
 
     /**
      * Send a message to keyguard telling it the screen just turned on.
-     * @see #onScreenTurnedOn()
+     * @see #onScreenTurnedOn
      * @see #handleNotifyScreenOn
      */
     private void notifyScreenOnLocked(IKeyguardShowCallback result) {
@@ -1049,7 +997,7 @@
 
     /**
      * Send message to keyguard telling it to show itself
-     * @see #handleShow()
+     * @see #handleShow
      */
     private void showLocked(Bundle options) {
         if (DEBUG) Log.d(TAG, "showLocked");
@@ -1130,7 +1078,7 @@
                     handleHide();
                     break;
                 case RESET:
-                    handleReset((Bundle) msg.obj);
+                    handleReset();
                     break;
                 case VERIFY_UNLOCK:
                     handleVerifyUnlock();
@@ -1150,23 +1098,14 @@
                 case KEYGUARD_DONE_AUTHENTICATING:
                     keyguardDone(true, true);
                     break;
-                case SET_HIDDEN:
-                    handleSetHidden(msg.arg1 != 0);
+                case SET_OCCLUDED:
+                    handleSetOccluded(msg.arg1 != 0);
                     break;
                 case KEYGUARD_TIMEOUT:
                     synchronized (KeyguardViewMediator.this) {
                         doKeyguardLocked((Bundle) msg.obj);
                     }
                     break;
-                case SHOW_ASSISTANT:
-                    handleShowAssistant();
-                    break;
-                case DISPATCH_EVENT:
-                    handleDispatchEvent((MotionEvent) msg.obj);
-                    break;
-                case LAUNCH_CAMERA:
-                    handleLaunchCamera();
-                    break;
                 case DISMISS:
                     handleDismiss();
                     break;
@@ -1206,21 +1145,13 @@
         sendUserPresentBroadcast();
     }
 
-    protected void handleLaunchCamera() {
-        mKeyguardViewManager.launchCamera();
-    }
-
-    protected void handleDispatchEvent(MotionEvent event) {
-        mKeyguardViewManager.dispatch(event);
-    }
-
     private void sendUserPresentBroadcast() {
         final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser());
         mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, currentUser);
     }
 
     /**
-     * @see #keyguardDoneDrawing
+     * @see #keyguardDone
      * @see #KEYGUARD_DONE_DRAWING
      */
     private void handleKeyguardDoneDrawing() {
@@ -1269,7 +1200,7 @@
 
     private void updateActivityLockScreenState() {
         try {
-            ActivityManagerNative.getDefault().setLockScreenShown(mShowing && !mHidden);
+            ActivityManagerNative.getDefault().setLockScreenShown(mShowing && !mOccluded);
         } catch (RemoteException e) {
         }
     }
@@ -1287,16 +1218,12 @@
                 if (DEBUG) Log.d(TAG, "handleShow");
             }
 
-            mKeyguardViewManager.show(options);
+            mStatusBarKeyguardViewManager.show(options);
             mShowing = true;
             mKeyguardDonePending = false;
             updateActivityLockScreenState();
             adjustStatusBarLocked();
             userActivity();
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs("lock");
-            } catch (RemoteException e) {
-            }
 
             // Do this at the end to not slow down display of the keyguard.
             playSounds(true);
@@ -1320,7 +1247,7 @@
                 playSounds(false);
             }
 
-            mKeyguardViewManager.hide();
+            mStatusBarKeyguardViewManager.hide();
             mShowing = false;
             mKeyguardDonePending = false;
             updateActivityLockScreenState();
@@ -1360,7 +1287,7 @@
             }
 
             if (DEBUG) {
-                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mHidden=" + mHidden
+                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mOccluded=" + mOccluded
                         + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
             }
 
@@ -1371,17 +1298,13 @@
     }
 
     /**
-     * Handle message sent by {@link #resetStateLocked(Bundle)}
+     * Handle message sent by {@link #resetStateLocked}
      * @see #RESET
      */
-    private void handleReset(Bundle options) {
-        if (options == null) {
-            options = new Bundle();
-        }
-        options.putBoolean(KeyguardViewManager.IS_SWITCHING_USER, mSwitchingUser);
+    private void handleReset() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleReset");
-            mKeyguardViewManager.reset(options);
+            mStatusBarKeyguardViewManager.reset();
         }
     }
 
@@ -1392,7 +1315,7 @@
     private void handleVerifyUnlock() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
-            mKeyguardViewManager.verifyUnlock();
+            mStatusBarKeyguardViewManager.verifyUnlock();
             mShowing = true;
             updateActivityLockScreenState();
         }
@@ -1405,18 +1328,18 @@
     private void handleNotifyScreenOff() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleNotifyScreenOff");
-            mKeyguardViewManager.onScreenTurnedOff();
+            mStatusBarKeyguardViewManager.onScreenTurnedOff();
         }
     }
 
     /**
-     * Handle message sent by {@link #notifyScreenOnLocked()}
+     * Handle message sent by {@link #notifyScreenOnLocked}
      * @see #NOTIFY_SCREEN_ON
      */
     private void handleNotifyScreenOn(IKeyguardShowCallback callback) {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleNotifyScreenOn");
-            mKeyguardViewManager.onScreenTurnedOn(callback);
+            mStatusBarKeyguardViewManager.onScreenTurnedOn(callback);
         }
     }
 
@@ -1424,35 +1347,23 @@
         return mKeyguardDonePending || !isSecure();
     }
 
-    public void showAssistant() {
-        Message msg = mHandler.obtainMessage(SHOW_ASSISTANT);
-        mHandler.sendMessage(msg);
-    }
-
-    public void handleShowAssistant() {
-        mKeyguardViewManager.showAssistant();
-    }
-
     private boolean isAssistantAvailable() {
         return mSearchManager != null
                 && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
     }
 
-    public static MultiUserAvatarCache getAvatarCache() {
-        return sMultiUserAvatarCache;
-    }
-
-    public void dispatch(MotionEvent event) {
-        Message msg = mHandler.obtainMessage(DISPATCH_EVENT, event);
-        mHandler.sendMessage(msg);
-    }
-
-    public void launchCamera() {
-        Message msg = mHandler.obtainMessage(LAUNCH_CAMERA);
-        mHandler.sendMessage(msg);
-    }
-
     public void onBootCompleted() {
         mUpdateMonitor.dispatchBootCompleted();
     }
+
+    public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
+            ViewGroup container, StatusBarWindowManager statusBarWindowManager) {
+        mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
+                statusBarWindowManager);
+        return mStatusBarKeyguardViewManager;
+    }
+
+    public ViewMediatorCallback getViewMediatorCallback() {
+        return mViewMediatorCallback;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index eb09335..aa4e69a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -17,10 +17,12 @@
 package com.android.systemui.recent;
 
 import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
@@ -30,7 +32,9 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -162,9 +166,14 @@
             intent.setComponent(origActivity);
         }
         final PackageManager pm = mContext.getPackageManager();
+        final IPackageManager ipm = AppGlobals.getPackageManager();
         intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                 | Intent.FLAG_ACTIVITY_NEW_TASK);
-        final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+        ResolveInfo resolveInfo = null;
+        try {
+            resolveInfo = ipm.resolveIntent(intent, null, 0, userId);
+        } catch (RemoteException re) {
+        }
         if (resolveInfo != null) {
             final ActivityInfo info = resolveInfo.activityInfo;
             final String title = info.loadLabel(pm).toString();
@@ -192,7 +201,11 @@
         final PackageManager pm = mContext.getPackageManager();
         Bitmap thumbnail = am.getTaskTopThumbnail(td.persistentTaskId);
         Drawable icon = getFullResIcon(td.resolveInfo, pm);
-
+        if (td.userId != UserHandle.myUserId()) {
+            // Need to badge the icon
+            final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            icon = um.getBadgedDrawableForUser(icon, new UserHandle(td.userId));
+        }
         if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
                 + td + ": " + thumbnail);
         synchronized (td) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
index b085211..95ab8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
@@ -24,9 +24,6 @@
      * P3 (1.0, 1.0)
      *
      * Values sampled with x at regular intervals between 0 and 1.
-     *
-     * These values were generated using:
-     *   ./scripts/bezier_interpolator_values_gen.py 0.4 0.2
      */
     private static final float[] VALUES = new float[] {
         0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index cde17f5e..64770a4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -28,8 +28,9 @@
         public static class App {
             public static final boolean EnableTaskFiltering = true;
             public static final boolean EnableTaskStackClipping = false;
-            public static final boolean EnableToggleNewRecentsActivity = false;
-            // This disables the bitmap and icon caches to
+            public static final boolean EnableInfoPane = true;
+
+            // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // For debugging, this enables us to create mock recents tasks
             public static final boolean EnableSystemServicesProxy = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f61c28c..f61c9f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -50,11 +50,7 @@
             String action = intent.getAction();
             Console.log(Constants.DebugFlags.App.SystemUIHandshake,
                     "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
-            if (action.equals(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY)) {
-                if (Constants.DebugFlags.App.EnableToggleNewRecentsActivity) {
-                    finish();
-                }
-            } else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
+            if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // Try and unfilter and filtered stacks
                 if (!mRecentsView.unfilterFilteredStacks()) {
                     // If there are no filtered stacks, dismiss recents and launch the first task
@@ -190,7 +186,6 @@
         // Register the broadcast receiver to handle messages from our service
         IntentFilter filter = new IntentFilter();
         filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
-        filter.addAction(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY);
         registerReceiver(mServiceBroadcastReceiver, filter);
 
         // Register the broadcast receiver to handle messages when the screen is turned off
@@ -224,11 +219,6 @@
                 Console.AnsiRed);
         super.onStop();
 
-        // Finish the current recents activity after we have launched a task
-        if (mTaskLaunched && Constants.DebugFlags.App.EnableToggleNewRecentsActivity) {
-            finish();
-        }
-
         mVisible = false;
         mTaskLaunched = false;
     }
@@ -250,8 +240,18 @@
 
     @Override
     public void onBackPressed() {
-        if (!mRecentsView.unfilterFilteredStacks()) {
-            super.onBackPressed();
+        boolean interceptedByInfoPanelClose = false;
+
+        // Try and return from any open info panes
+        if (Constants.DebugFlags.App.EnableInfoPane) {
+            interceptedByInfoPanelClose = mRecentsView.closeOpenInfoPanes();
+        }
+
+        // If we haven't been intercepted already, then unfilter any stacks
+        if (!interceptedByInfoPanelClose) {
+            if (!mRecentsView.unfilterFilteredStacks()) {
+                super.onBackPressed();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 21460bb..9fdb5f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -40,6 +40,8 @@
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
     public int taskBarEnterAnimDuration;
+    public int taskStackScrollDismissInfoPaneDistance;
+    public int taskViewInfoPaneAnimDuration;
 
     public boolean launchedWithThumbnailAnimation;
 
@@ -81,8 +83,13 @@
                 res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
         taskBarEnterAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
+        taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize(
+                R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance);
+        taskViewInfoPaneAnimDuration =
+                res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
     }
 
+    /** Updates the system insets */
     public void updateSystemInsets(Rect insets) {
         systemInsets.set(insets);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index f78a999..06ca9e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -112,7 +112,6 @@
 
 /* Service */
 public class RecentsService extends Service {
-    final static String ACTION_FINISH_RECENTS_ACTIVITY = "action_finish_recents_activity";
     final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
 
     Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 3c34e90..fd0f6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -192,8 +192,9 @@
                                     " forceLoad: " + forceLoadTask);
                     // Load the application icon
                     if (loadIcon == null || forceLoadTask) {
-                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent());
-                        Drawable icon = ssp.getActivityIcon(info);
+                        ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
+                                t.userId);
+                        Drawable icon = ssp.getActivityIcon(info, t.userId);
                         if (!mCancelled) {
                             if (icon != null) {
                                 Console.log(Constants.DebugFlags.App.TaskDataLoader,
@@ -411,7 +412,7 @@
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = tasks.get(i);
-            ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent());
+            ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
                     t.activityLabel.toString());
             Bitmap activityIcon = t.activityIcon;
@@ -437,7 +438,7 @@
                     }
                 }
                 if (task.applicationIcon == null) {
-                    task.applicationIcon = ssp.getActivityIcon(info);
+                    task.applicationIcon = ssp.getActivityIcon(info, task.userId);
                     if (task.applicationIcon != null) {
                         mApplicationIconCache.put(task.key, task.applicationIcon);
                     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 505238d..7f0d9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -18,14 +18,19 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,6 +43,8 @@
 public class SystemServicesProxy {
     ActivityManager mAm;
     PackageManager mPm;
+    IPackageManager mIpm;
+    UserManager mUm;
     String mPackage;
 
     Bitmap mDummyIcon;
@@ -46,6 +53,8 @@
     public SystemServicesProxy(Context context) {
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         mPm = context.getPackageManager();
+        mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mIpm = AppGlobals.getPackageManager();
         mPackage = context.getPackageName();
 
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
@@ -142,14 +151,19 @@
         mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
-    /** Returns the activity info for a given component name */
-    public ActivityInfo getActivityInfo(ComponentName cn) {
-        if (mPm == null) return null;
+    /**
+     * Returns the activity info for a given component name.
+     * 
+     * @param ComponentName The component name of the activity.
+     * @param userId The userId of the user that this is for.
+     */
+    public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
+        if (mIpm == null) return null;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
 
         try {
-            return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
-        } catch (PackageManager.NameNotFoundException e) {
+            return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
+        } catch (RemoteException e) {
             e.printStackTrace();
             return null;
         }
@@ -167,15 +181,22 @@
         return info.loadLabel(mPm).toString();
     }
 
-    /** Returns the activity icon */
-    public Drawable getActivityIcon(ActivityInfo info) {
-        if (mPm == null) return null;
+    /**
+     * Returns the activity icon for the ActivityInfo for a user, badging if
+     * necessary.
+     */
+    public Drawable getActivityIcon(ActivityInfo info, int userId) {
+        if (mPm == null || mUm == null) return null;
 
         // If we are mocking, then return a mock label
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             return new ColorDrawable(0xFF666666);
         }
 
-        return info.loadIcon(mPm);
+        Drawable icon = info.loadIcon(mPm);
+        if (userId != UserHandle.myUserId()) {
+            icon = mUm.getBadgedDrawableForUser(icon, new UserHandle(userId));
+        }
+        return icon;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 189f358..ff062f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -37,25 +37,33 @@
     public static class TaskKey {
         public final int id;
         public final Intent baseIntent;
+        public final int userId;
 
-        public TaskKey(int id, Intent intent) {
+        public TaskKey(int id, Intent intent, int userId) {
             this.id = id;
             this.baseIntent = intent;
+            this.userId = userId;
         }
 
         @Override
         public boolean equals(Object o) {
-            return hashCode() == o.hashCode();
+            if (!(o instanceof TaskKey)) {
+                return false;
+            }
+            return id == ((TaskKey) o).id
+                    && userId == ((TaskKey) o).userId;
         }
 
         @Override
         public int hashCode() {
-            return id;
+            return (id << 5) + userId;
         }
 
         @Override
         public String toString() {
-            return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
+            return "Task.Key: " + id + ", "
+                    + "u" + userId + ", "
+                    + baseIntent.getComponent().getPackageName();
         }
     }
 
@@ -75,7 +83,7 @@
 
     public Task(int id, boolean isActive, Intent intent, String activityTitle,
                 Bitmap activityIcon, int userId) {
-        this.key = new TaskKey(id, intent);
+        this.key = new TaskKey(id, intent, userId);
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
         this.isActive = isActive;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 21e2c1d..d2de185 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -134,9 +134,9 @@
         /* Notifies when a task has been removed from the stack */
         public void onStackTaskRemoved(TaskStack stack, Task t);
         /** Notifies when the stack was filtered */
-        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
+        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
         /** Notifies when the stack was un-filtered */
-        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
+        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
     }
 
     Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index ec28379..b054a22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -17,13 +17,16 @@
 package com.android.systemui.recents.views;
 
 import android.app.ActivityOptions;
+import android.app.TaskStackBuilder;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.net.Uri;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.FrameLayout;
 import com.android.systemui.recents.Console;
@@ -179,6 +182,21 @@
         return true;
     }
 
+    /** Closes any open info panes */
+    public boolean closeOpenInfoPanes() {
+        if (mBSP != null) {
+            // Get the first stack view
+            int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                TaskStackView stackView = (TaskStackView) getChildAt(i);
+                if (stackView.closeOpenInfoPanes()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /** Unfilters any filtered stacks */
     public boolean unfilterFilteredStacks() {
         if (mBSP != null) {
@@ -206,6 +224,9 @@
             mCb.onTaskLaunching();
         }
 
+        // Close any open info panes
+        closeOpenInfoPanes();
+
         final Runnable launchRunnable = new Runnable() {
             @Override
             public void run() {
@@ -283,4 +304,15 @@
             tv.animateOnLeavingRecents(launchRunnable);
         }
     }
+
+    @Override
+    public void onTaskAppInfoLaunched(Task t) {
+        // Create a new task stack with the application info details activity
+        Intent baseIntent = t.key.baseIntent;
+        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
+        intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
+        TaskStackBuilder.create(getContext())
+                .addNextIntentWithParentStack(intent).startActivities();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
new file mode 100644
index 0000000..233e38c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 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.systemui.recents.views;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import com.android.systemui.R;
+import com.android.systemui.recents.BakedBezierInterpolator;
+import com.android.systemui.recents.Utilities;
+
+
+/* The task info view */
+class TaskInfoView extends FrameLayout {
+
+    Button mAppInfoButton;
+
+    // Circular clip animation
+    boolean mCircularClipEnabled;
+    Path mClipPath = new Path();
+    float mClipRadius;
+    float mMaxClipRadius;
+    Point mClipOrigin = new Point();
+    ObjectAnimator mCircularClipAnimator;
+
+    public TaskInfoView(Context context) {
+        this(context, null);
+    }
+
+    public TaskInfoView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        // Initialize the buttons on the info panel
+        mAppInfoButton = (Button) findViewById(R.id.task_view_app_info_button);
+    }
+
+    /** Updates the positions of each of the items to fit in the rect specified */
+    void updateContents(Rect visibleRect) {
+        // Offset the app info button
+        LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams();
+        lp.topMargin = visibleRect.top +
+                (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2;
+        requestLayout();
+    }
+
+    /** Sets the circular clip radius on this panel */
+    public void setCircularClipRadius(float r) {
+        mClipRadius = r;
+        invalidate();
+    }
+
+    /** Gets the circular clip radius on this panel */
+    public float getCircularClipRadius() {
+        return mClipRadius;
+    }
+
+    /** Animates the circular clip radius on the icon */
+    void animateCircularClip(Point o, float fromRadius, float toRadius,
+                             final Runnable postRunnable, boolean animateInContent) {
+        if (mCircularClipAnimator != null) {
+            mCircularClipAnimator.cancel();
+        }
+
+        // Calculate the max clip radius to each of the corners
+        int w = getMeasuredWidth() - o.x;
+        int h = getMeasuredHeight() - o.y;
+        // origin to tl, tr, br, bl
+        mMaxClipRadius = (int) Math.ceil(Math.sqrt(o.x * o.x + o.y * o.y));
+        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + o.y * o.y)));
+        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + h * h)));
+        mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(o.x * o.x + h * h)));
+
+        mClipOrigin.set(o.x, o.y);
+        mClipRadius = fromRadius;
+        int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
+        mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
+        mCircularClipAnimator.setDuration(duration);
+        mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mCircularClipEnabled = false;
+                if (postRunnable != null) {
+                    postRunnable.run();
+                }
+            }
+        });
+        mCircularClipAnimator.start();
+        mCircularClipEnabled = true;
+
+        if (animateInContent) {
+            animateAppInfoButtonIn(duration);
+        }
+    }
+
+    /** Cancels the circular clip animation. */
+    void cancelCircularClipAnimation() {
+        if (mCircularClipAnimator != null) {
+            mCircularClipAnimator.cancel();
+        }
+    }
+
+    void animateAppInfoButtonIn(int duration) {
+        mAppInfoButton.setScaleX(0.75f);
+        mAppInfoButton.setScaleY(0.75f);
+        mAppInfoButton.animate()
+                .scaleX(1f)
+                .scaleY(1f)
+                .setDuration(duration)
+                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .withLayer()
+                .start();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        int saveCount = 0;
+        if (mCircularClipEnabled) {
+            saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
+            mClipPath.reset();
+            mClipPath.addCircle(mClipOrigin.x, mClipOrigin.y, mClipRadius * mMaxClipRadius,
+                    Path.Direction.CW);
+            canvas.clipPath(mClipPath);
+        }
+        super.draw(canvas);
+        if (mCircularClipEnabled) {
+            canvas.restoreToCount(saveCount);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 728aaad..033bd67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -26,6 +26,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -45,16 +46,18 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>,
-        View.OnClickListener {
+        View.OnClickListener, View.OnLongClickListener {
 
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t);
+        public void onTaskAppInfoLaunched(Task t);
     }
 
     TaskStack mStack;
@@ -73,12 +76,10 @@
     int mMinScroll;
     int mMaxScroll;
     int mStashedScroll;
+    int mLastInfoPaneStackScroll;
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
 
-    // Filtering
-    AnimatorSet mFilterChildrenAnimator;
-
     // Optimizations
     int mHwLayersRefCount;
     int mStackViewsAnimationDuration;
@@ -282,6 +283,17 @@
     public void setStackScroll(int value) {
         mStackScroll = value;
         requestSynchronizeStackViewsWithModel();
+
+        // Close any open info panes if the user has scrolled away from them
+        boolean isAnimatingScroll = (mScrollAnimator != null && mScrollAnimator.isRunning());
+        if (mLastInfoPaneStackScroll > -1 && !isAnimatingScroll) {
+            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            if (Math.abs(mStackScroll - mLastInfoPaneStackScroll) >
+                    config.taskStackScrollDismissInfoPaneDistance) {
+                // Close any open info panes
+                closeOpenInfoPanes();
+            }
+        }
     }
     /** Sets the current stack scroll without synchronizing the stack view with the model */
     public void setStackScrollRaw(int value) {
@@ -301,19 +313,24 @@
             // Enable hw layers on the stack
             addHwLayersRefCount("animateBoundScroll");
 
-            // Abort any current animations
-            abortScroller();
-            abortBoundScrollAnimation();
-
             // Start a new scroll animation
-            animateScroll(curScroll, newScroll);
-            mScrollAnimator.start();
+            animateScroll(curScroll, newScroll, new Runnable() {
+                @Override
+                public void run() {
+                    // Disable hw layers on the stack
+                    decHwLayersRefCount("animateBoundScroll");
+                }
+            });
         }
         return mScrollAnimator;
     }
 
     /** Animates the stack scroll */
-    void animateScroll(int curScroll, int newScroll) {
+    void animateScroll(int curScroll, int newScroll, final Runnable postRunnable) {
+        // Abort any current animations
+        abortScroller();
+        abortBoundScrollAnimation();
+
         mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
                 curScroll, 250));
@@ -327,20 +344,23 @@
         mScrollAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                // Disable hw layers on the stack
-                decHwLayersRefCount("animateBoundScroll");
+                if (postRunnable != null) {
+                    postRunnable.run();
+                }
+                mScrollAnimator.removeAllListeners();
             }
         });
+        mScrollAnimator.start();
     }
 
     /** Aborts any current stack scrolls */
     void abortBoundScrollAnimation() {
         if (mScrollAnimator != null) {
             mScrollAnimator.cancel();
-            mScrollAnimator.removeAllListeners();
         }
     }
 
+    /** Aborts the scroller and any current fling */
     void abortScroller() {
         if (!mScroller.isFinished()) {
             // Abort the scroller
@@ -408,6 +428,21 @@
         }
     }
 
+    /** Closes any open info panes. */
+    boolean closeOpenInfoPanes() {
+        if (!Constants.DebugFlags.App.EnableInfoPane) return false;
+
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TaskView tv = (TaskView) getChildAt(i);
+            if (tv.isInfoPaneVisible()) {
+                tv.hideInfoPane();
+                return true;
+            }
+        }
+        return false;
+    }
+
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
         Console.log(Constants.DebugFlags.UI.HwLayers,
@@ -645,163 +680,21 @@
         requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
     }
 
-    @Override
-    public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
-                                Task filteredTask) {
-        // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
-        // (filtered) stack
-        // XXX: Use HW Layers
-
-        // Stash the scroll and filtered task for us to restore to when we unfilter
-        mStashedScroll = getStackScroll();
-
-        // Compute the transforms of the items in the current stack
-        final ArrayList<TaskViewTransform> curTaskTransforms =
-                getStackTransforms(curStack, mStashedScroll, null, true);
-
-        // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
-        updateMinMaxScroll(false);
-        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
-        setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
-        boundScrollRaw();
-
-        // Compute the transforms of the items in the new stack after setting the new scroll
-        final ArrayList<TaskViewTransform> taskTransforms =
-                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
-        // Animate all of the existing views on screen either out of view (if they are not visible
-        // in the new stack) or to their final positions in the new stack
-        final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
-        final ArrayList<Task> tasks = mStack.getTasks();
-        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
-        int childCount = getChildCount();
-        int movement = 0;
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
-            Task task = tv.getTask();
-            TaskViewTransform toTransform;
-            int taskIndex = tasks.indexOf(task);
-
-            boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible;
-            if (willBeInvisible) {
-                // Compose a new transform that fades and slides the task out of view
-                TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
-                toTransform = new TaskViewTransform(fromTransform);
-                tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-                tv.prepareTaskTransformForFilterTaskHidden(toTransform);
-
-                childrenToReturnToPool.add(tv);
-            } else {
-                toTransform = taskTransforms.get(taskIndex);
-
-                // Use the movement of the visible views to calculate the duration of the animation
-                movement = Math.max(movement,
-                        Math.abs(toTransform.translationY - (int) tv.getTranslationY()));
-            }
-            childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
-        }
-
-        // Cancel the previous animation
-        if (mFilterChildrenAnimator != null) {
-            mFilterChildrenAnimator.cancel();
-            mFilterChildrenAnimator.removeAllListeners();
-        }
-
-        // Create a new animation for the existing children
-        final RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mFilterChildrenAnimator = new AnimatorSet();
-        mFilterChildrenAnimator.setDuration(
-                Utilities.calculateTranslationAnimationDuration(movement,
-                        config.filteringCurrentViewsMinAnimDuration));
-        mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-        mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-            boolean isCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                isCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (isCancelled) return;
-
-                // Return all the removed children to the view pool
-                for (TaskView tv : childrenToReturnToPool) {
-                    mViewPool.returnViewToPool(tv);
-                }
-
-                // For views that are not already visible, animate them in
-                ArrayList<Animator> newViewsAnims = new ArrayList<Animator>();
-                int taskCount = tasks.size();
-                int movement = 0;
-                int offset = 0;
-                for (int i = 0; i < taskCount; i++) {
-                    Task task = tasks.get(i);
-                    TaskViewTransform toTransform = taskTransforms.get(i);
-                    if (toTransform.visible) {
-                        TaskViewTransform fromTransform =
-                                curTaskTransforms.get(curStack.indexOf(task));
-                        TaskView tv = getChildViewForTask(task);
-                        if (tv == null) {
-                            tv = mViewPool.pickUpViewFromPool(task, task);
-                            // Compose a new transform that fades and slides the new task in
-                            fromTransform = new TaskViewTransform(toTransform);
-                            tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
-                            tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
-                            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-                            anim.setStartDelay(offset *
-                                    Constants.Values.TaskStackView.FilterStartDelay);
-                            newViewsAnims.add(anim);
-
-                            // Use the movement of the newly visible views to calculate the duration
-                            // of the animation
-                            movement = Math.max(movement, Math.abs(toTransform.translationY -
-                                    fromTransform.translationY));
-                            offset++;
-                        }
-                    }
-
-                    // Animate the new views in
-                    mFilterChildrenAnimator = new AnimatorSet();
-                    mFilterChildrenAnimator.setDuration(
-                            Utilities.calculateTranslationAnimationDuration(movement,
-                                    config.filteringNewViewsMinAnimDuration));
-                    mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-                    mFilterChildrenAnimator.playTogether(newViewsAnims);
-                    mFilterChildrenAnimator.start();
-                }
-                invalidate();
-            }
-        });
-        mFilterChildrenAnimator.playTogether(childViewAnims);
-        mFilterChildrenAnimator.start();
-    }
-
-    @Override
-    public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
-        // Compute the transforms of the items in the current stack
-        final int curScroll = getStackScroll();
-        final ArrayList<TaskViewTransform> curTaskTransforms =
-                getStackTransforms(curStack, curScroll, null, true);
-
-        // Restore the stashed scroll
-        updateMinMaxScroll(false);
-        setStackScrollRaw(mStashedScroll);
-        boundScrollRaw();
-
-        // Compute the transforms of the items in the new stack after restoring the stashed scroll
-        final ArrayList<TaskViewTransform> taskTransforms =
-                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
-
+    /**
+     * Creates the animations for all the children views that need to be removed or to move views
+     * to their un/filtered position when we are un/filtering a stack, and returns the duration
+     * for these animations.
+     */
+    int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks,
+                        ArrayList<TaskViewTransform> curTaskTransforms,
+                        ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms,
+                        HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+                        ArrayList<TaskView> childrenToRemoveOut,
+                        RecentsConfiguration config) {
         // Animate all of the existing views out of view (if they are not in the visible range in
         // the new stack) or to their final positions in the new stack
-        final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
-        final ArrayList<Task> tasks = mStack.getTasks();
-        ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
-        int childCount = getChildCount();
         int movement = 0;
+        int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             TaskView tv = (TaskView) getChildAt(i);
             Task task = tv.getTask();
@@ -811,104 +704,172 @@
             // If the view is no longer visible, then we should just animate it out
             boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible;
             if (willBeInvisible) {
-                toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+                if (taskIndex < 0) {
+                    toTransform = curTaskTransforms.get(curTasks.indexOf(task));
+                } else {
+                    toTransform = new TaskViewTransform(taskTransforms.get(taskIndex));
+                }
                 tv.prepareTaskTransformForFilterTaskVisible(toTransform);
-                childrenToRemove.add(tv);
+                childrenToRemoveOut.add(tv);
             } else {
                 toTransform = taskTransforms.get(taskIndex);
                 // Use the movement of the visible views to calculate the duration of the animation
                 movement = Math.max(movement, Math.abs(toTransform.translationY -
                         (int) tv.getTranslationY()));
             }
-
-            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-            childViewAnims.add(anim);
+            childViewTransformsOut.put(tv, new Pair(0, toTransform));
         }
+        return Utilities.calculateTranslationAnimationDuration(movement,
+                config.filteringCurrentViewsMinAnimDuration);
+    }
 
-        // Cancel the previous animation
-        if (mFilterChildrenAnimator != null) {
-            mFilterChildrenAnimator.cancel();
-            mFilterChildrenAnimator.removeAllListeners();
+    /**
+     * Creates the animations for all the children views that need to be animated in when we are
+     * un/filtering a stack, and returns the duration for these animations.
+     */
+    int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks,
+                         ArrayList<TaskViewTransform> taskTransforms,
+                         HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
+                         RecentsConfiguration config) {
+        int offset = 0;
+        int movement = 0;
+        int taskCount = tasks.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            Task task = tasks.get(i);
+            TaskViewTransform toTransform = taskTransforms.get(i);
+            if (toTransform.visible) {
+                TaskView tv = getChildViewForTask(task);
+                if (tv == null) {
+                    // For views that are not already visible, animate them in
+                    tv = mViewPool.pickUpViewFromPool(task, task);
+
+                    // Compose a new transform to fade and slide the new task in
+                    TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+                    tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+                    tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+
+                    int startDelay = offset *
+                            Constants.Values.TaskStackView.FilterStartDelay;
+                    childViewTransformsOut.put(tv, new Pair(startDelay, toTransform));
+
+                    // Use the movement of the new views to calculate the duration of the animation
+                    movement = Math.max(movement,
+                            Math.abs(toTransform.translationY - fromTransform.translationY));
+                    offset++;
+                }
+            }
         }
+        return Utilities.calculateTranslationAnimationDuration(movement,
+                config.filteringNewViewsMinAnimDuration);
+    }
 
-        // Create a new animation for the existing children
+    /** Orchestrates the animations of the current child views and any new views. */
+    void doFilteringAnimation(ArrayList<Task> curTasks,
+                              ArrayList<TaskViewTransform> curTaskTransforms,
+                              final ArrayList<Task> tasks,
+                              final ArrayList<TaskViewTransform> taskTransforms) {
         final RecentsConfiguration config = RecentsConfiguration.getInstance();
-        mFilterChildrenAnimator = new AnimatorSet();
-        mFilterChildrenAnimator.setDuration(
-                Utilities.calculateTranslationAnimationDuration(movement,
-                        config.filteringCurrentViewsMinAnimDuration));
-        mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
-        mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-            boolean isCancelled;
 
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                isCancelled = true;
-            }
+        // Calculate the transforms to animate out all the existing views if they are not in the
+        // new visible range (or to their final positions in the stack if they are)
+        final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
+        final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms =
+                new HashMap<TaskView, Pair<Integer, TaskViewTransform>>();
+        int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks,
+                taskTransforms, childViewTransforms, childrenToRemove, config);
 
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (isCancelled) return;
+        // If all the current views are in the visible range of the new stack, then don't wait for
+        // views to animate out and animate all the new views into their place
+        final boolean unifyNewViewAnimation = childrenToRemove.isEmpty();
+        if (unifyNewViewAnimation) {
+            int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms,
+                    childViewTransforms, config);
+            duration = Math.max(duration, inDuration);
+        }
 
-                // Return all the removed children to the view pool
-                for (TaskView tv : childrenToRemove) {
-                    mViewPool.returnViewToPool(tv);
-                }
+        // Animate all the views to their final transforms
+        for (final TaskView tv : childViewTransforms.keySet()) {
+            Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+            tv.animate().cancel();
+            tv.animate()
+                    .setStartDelay(t.first)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            childViewTransforms.remove(tv);
+                            if (childViewTransforms.isEmpty()) {
+                                // Return all the removed children to the view pool
+                                for (TaskView tv : childrenToRemove) {
+                                    mViewPool.returnViewToPool(tv);
+                                }
 
-                // Increment the hw layers ref count
-                addHwLayersRefCount("unfilteredNewViews");
-
-                // For views that are not already visible, animate them in
-                ArrayList<Animator> newViewAnims = new ArrayList<Animator>();
-                int taskCount = tasks.size();
-                int movement = 0;
-                int offset = 0;
-                for (int i = 0; i < taskCount; i++) {
-                    Task task = tasks.get(i);
-                    TaskViewTransform toTransform = taskTransforms.get(i);
-                    if (toTransform.visible) {
-                        TaskView tv = getChildViewForTask(task);
-                        if (tv == null) {
-                            // For views that are not already visible, animate them in
-                            tv = mViewPool.pickUpViewFromPool(task, task);
-
-                            // Compose a new transform to fade and slide the new task in
-                            TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
-                            tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
-                            tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
-
-                            Animator anim = tv.getAnimatorToTaskTransform(toTransform);
-                            anim.setStartDelay(offset *
-                                    Constants.Values.TaskStackView.FilterStartDelay);
-                            newViewAnims.add(anim);
-                            // Use the movement of the newly visible views to calculate the duration
-                            // of the animation
-                            movement = Math.max(movement,
-                                    Math.abs(toTransform.translationY - fromTransform.translationY));
-                            offset++;
+                                if (!unifyNewViewAnimation) {
+                                    // For views that are not already visible, animate them in
+                                    childViewTransforms.clear();
+                                    int duration = getEnterTransformsForFilterAnimation(tasks,
+                                            taskTransforms, childViewTransforms, config);
+                                    for (final TaskView tv : childViewTransforms.keySet()) {
+                                        Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
+                                        tv.animate().setStartDelay(t.first);
+                                        tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+                                    }
+                                }
+                            }
                         }
-                    }
-                }
+                    });
+            tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+        }
+    }
 
-                // Run the animation
-                mFilterChildrenAnimator = new AnimatorSet();
-                mFilterChildrenAnimator.setDuration(
-                        Utilities.calculateTranslationAnimationDuration(movement,
-                                config.filteringNewViewsMinAnimDuration));
-                mFilterChildrenAnimator.playTogether(newViewAnims);
-                mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        // Decrement the hw layers ref count
-                        decHwLayersRefCount("unfilteredNewViews");
-                    }
-                });
-                mFilterChildrenAnimator.start();
-                invalidate();
-            }
-        });
-        mFilterChildrenAnimator.playTogether(childViewAnims);
-        mFilterChildrenAnimator.start();
+    @Override
+    public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks,
+                                Task filteredTask) {
+        // Close any open info panes
+        closeOpenInfoPanes();
+
+        // Stash the scroll and filtered task for us to restore to when we unfilter
+        mStashedScroll = getStackScroll();
+
+        // Calculate the current task transforms
+        ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curTasks, getStackScroll(), null, true);
+
+        // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better
+        updateMinMaxScroll(false);
+        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
+        setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight));
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack after setting the new scroll
+        final ArrayList<Task> tasks = mStack.getTasks();
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(mStack.getTasks(), getStackScroll(), null, true);
+
+        // Animate
+        doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
+    }
+
+    @Override
+    public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) {
+        // Close any open info panes
+        closeOpenInfoPanes();
+
+        // Calculate the current task transforms
+        final ArrayList<TaskViewTransform> curTaskTransforms =
+                getStackTransforms(curTasks, getStackScroll(), null, true);
+
+        // Restore the stashed scroll
+        updateMinMaxScroll(false);
+        setStackScrollRaw(mStashedScroll);
+        boundScrollRaw();
+
+        // Compute the transforms of the items in the new stack after restoring the stashed scroll
+        final ArrayList<Task> tasks = mStack.getTasks();
+        final ArrayList<TaskViewTransform> taskTransforms =
+                getStackTransforms(tasks, getStackScroll(), null, true);
+
+        // Animate
+        doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms);
 
         // Clear the saved vars
         mStashedScroll = 0;
@@ -972,6 +933,9 @@
 
             // Set the callbacks and listeners for this new view
             tv.setOnClickListener(this);
+            if (Constants.DebugFlags.App.EnableInfoPane) {
+                tv.setOnLongClickListener(this);
+            }
             tv.setCallbacks(this);
         } else {
             attachViewToParent(tv, insertIndex, tv.getLayoutParams());
@@ -1006,6 +970,24 @@
         }
     }
 
+    @Override
+    public void onTaskInfoPanelShown(TaskView tv) {
+        // Do nothing
+    }
+
+    @Override
+    public void onTaskInfoPanelHidden(TaskView tv) {
+        // Unset the saved scroll
+        mLastInfoPaneStackScroll = -1;
+    }
+
+    @Override
+    public void onTaskAppInfoClicked(TaskView tv) {
+        if (mCb != null) {
+            mCb.onTaskAppInfoLaunched(tv.getTask());
+        }
+    }
+
     /**** View.OnClickListener Implementation ****/
 
     @Override
@@ -1015,10 +997,51 @@
         Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
                 task + " cb: " + mCb);
 
+        // Close any open info panes if the user taps on another task
+        if (closeOpenInfoPanes()) {
+            return;
+        }
+
         if (mCb != null) {
             mCb.onTaskLaunched(this, tv, mStack, task);
         }
     }
+
+    @Override
+    public boolean onLongClick(View v) {
+        if (!Constants.DebugFlags.App.EnableInfoPane) return false;
+
+        TaskView tv = (TaskView) v;
+
+        // Close any other task info panels if we launch another info pane
+        closeOpenInfoPanes();
+
+        // Scroll the task view so that it is maximally visible
+        float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
+        int taskIndex = mStack.indexOfTask(tv.getTask());
+        int curScroll = getStackScroll();
+        int newScroll = (int) Math.max(mMinScroll, Math.min(mMaxScroll, taskIndex * overlapHeight));
+        TaskViewTransform transform = getStackTransform(taskIndex, curScroll);
+        Rect nonOverlapRect = new Rect(transform.rect);
+        if (taskIndex < (mStack.getTaskCount() - 1)) {
+            nonOverlapRect.bottom = nonOverlapRect.top + (int) overlapHeight;
+        }
+
+        // XXX: Use HW Layers
+        if (transform.t < 0f) {
+            animateScroll(curScroll, newScroll, null);
+        } else if (nonOverlapRect.bottom > mStackRectSansPeek.bottom) {
+            // Check if we are out of bounds, if so, just scroll it in such that the bottom of the
+            // task view is visible
+            newScroll = curScroll - (mStackRectSansPeek.bottom - nonOverlapRect.bottom);
+            animateScroll(curScroll, newScroll, null);
+        }
+        mLastInfoPaneStackScroll = newScroll;
+
+        // Show the info pane for this task view
+        tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight));
+        return true;
+    }
 }
 
 /* Handles touch events */
@@ -1233,9 +1256,10 @@
                 int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                 int x = (int) ev.getX(activePointerIndex);
                 int y = (int) ev.getY(activePointerIndex);
+                int yTotal = Math.abs(y - mInitialMotionY);
                 int deltaY = mLastMotionY - y;
                 if (!mIsScrolling) {
-                    if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
+                    if (yTotal > mScrollTouchSlop) {
                         mIsScrolling = true;
                         // Initialize the velocity tracker
                         initOrResetVelocityTracker();
@@ -1357,6 +1381,13 @@
         if (parent != null) {
             parent.requestDisallowInterceptTouchEvent(true);
         }
+        // If the info panel is currently showing on this view, then we need to dismiss it
+        if (Constants.DebugFlags.App.EnableInfoPane) {
+            TaskView tv = (TaskView) v;
+            if (tv.isInfoPaneVisible()) {
+                tv.hideInfoPane();
+            }
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index a3056ec..81805d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,39 +16,41 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Path;
+import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.BakedBezierInterpolator;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 
 
 /* A task view */
-public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks {
+public class TaskView extends FrameLayout implements View.OnClickListener,
+        Task.TaskCallbacks {
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         public void onTaskIconClicked(TaskView tv);
+        public void onTaskInfoPanelShown(TaskView tv);
+        public void onTaskInfoPanelHidden(TaskView tv);
+        public void onTaskAppInfoClicked(TaskView tv);
+
         // public void onTaskViewReboundToTask(TaskView tv, Task t);
     }
 
     Task mTask;
     boolean mTaskDataLoaded;
+    boolean mTaskInfoPaneVisible;
+    Point mLastTouchDown = new Point();
 
     TaskThumbnailView mThumbnailView;
     TaskBarView mBarView;
+    TaskInfoView mInfoView;
     TaskViewCallbacks mCb;
 
 
@@ -73,12 +75,24 @@
         // Bind the views
         mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
         mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
-        mBarView.mApplicationIcon.setOnClickListener(this);
+        mInfoView = (TaskInfoView) findViewById(R.id.task_view_info_pane);
+
         if (mTaskDataLoaded) {
             onTaskDataLoaded(false);
         }
     }
 
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE:
+                mLastTouchDown.set((int) ev.getX(), (int) ev.getY());
+                break;
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
     /** Set callback */
     void setCallbacks(TaskViewCallbacks cb) {
         mCb = cb;
@@ -115,18 +129,6 @@
         }
     }
 
-    /** Returns an animator to animate this task to the specified transform */
-    Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
-        AnimatorSet anims = new AnimatorSet();
-        anims.playTogether(
-                ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
-                ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
-                ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
-                ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
-        );
-        return anims;
-    }
-
     /** Resets this view's properties */
     void resetViewProperties() {
         setTranslationX(0f);
@@ -136,12 +138,20 @@
         setAlpha(1f);
     }
 
+    /**
+     * When we are un/filtering, this method will set up the transform that we are animating to,
+     * in order to hide the task.
+     */
     void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
         // Fade the view out and slide it away
         toTransform.alpha = 0f;
         toTransform.translationY += 200;
     }
 
+    /**
+     * When we are un/filtering, this method will setup the transform that we are animating from,
+     * in order to show the task.
+     */
     void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
         // Fade the view in
         fromTransform.alpha = 0f;
@@ -201,6 +211,63 @@
         return outRect;
     }
 
+    /** Returns whether this task has an info pane visible */
+    boolean isInfoPaneVisible() {
+        return mTaskInfoPaneVisible;
+    }
+
+    /** Shows the info pane if it is not visible. */
+    void showInfoPane(Rect taskVisibleRect) {
+        if (mTaskInfoPaneVisible) return;
+
+        // Remove the bar view from the visible rect and update the info pane contents
+        taskVisibleRect.top += mBarView.getMeasuredHeight();
+        mInfoView.updateContents(taskVisibleRect);
+
+        // Show the info pane and animate it into view
+        mInfoView.setVisibility(View.VISIBLE);
+        mInfoView.animateCircularClip(mLastTouchDown, 0f, 1f, null, true);
+        mInfoView.setOnClickListener(this);
+        mTaskInfoPaneVisible = true;
+
+        // Notify any callbacks
+        if (mCb != null) {
+            mCb.onTaskInfoPanelShown(this);
+        }
+    }
+
+    /** Hides the info pane if it is visible. */
+    void hideInfoPane() {
+        if (!mTaskInfoPaneVisible) return;
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+
+        // Cancel any circular clip animation
+        mInfoView.cancelCircularClipAnimation();
+
+        // Animate the info pane out
+        mInfoView.animate()
+                .alpha(0f)
+                .setDuration(config.taskViewInfoPaneAnimDuration)
+                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .withLayer()
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mInfoView.setVisibility(View.INVISIBLE);
+                        mInfoView.setOnClickListener(null);
+
+                        mInfoView.setAlpha(1f);
+                    }
+                })
+                .start();
+        mTaskInfoPaneVisible = false;
+
+        // Notify any callbacks
+        if (mCb != null) {
+            mCb.onTaskInfoPanelHidden(this);
+        }
+    }
+
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
         mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -221,27 +288,39 @@
 
     @Override
     public void onTaskDataLoaded(boolean reloadingTaskData) {
-        if (mThumbnailView != null && mBarView != null) {
+        if (mThumbnailView != null && mBarView != null && mInfoView != null) {
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask, reloadingTaskData);
             mBarView.rebindToTask(mTask, reloadingTaskData);
+            // Rebind any listeners
+            mBarView.mApplicationIcon.setOnClickListener(this);
+            mInfoView.mAppInfoButton.setOnClickListener(this);
         }
         mTaskDataLoaded = true;
     }
 
     @Override
     public void onTaskDataUnloaded() {
-        if (mThumbnailView != null && mBarView != null) {
+        if (mThumbnailView != null && mBarView != null && mInfoView != null) {
             // Unbind each of the views from the task data and remove the task callback
             mTask.setCallbacks(null);
             mThumbnailView.unbindFromTask();
             mBarView.unbindFromTask();
+            // Unbind any listeners
+            mBarView.mApplicationIcon.setOnClickListener(null);
+            mInfoView.mAppInfoButton.setOnClickListener(null);
         }
         mTaskDataLoaded = false;
     }
 
     @Override
     public void onClick(View v) {
-        mCb.onTaskIconClicked(this);
+        if (v == mInfoView) {
+            // Do nothing
+        } else if (v == mBarView.mApplicationIcon) {
+            mCb.onTaskIconClicked(this);
+        } else if (v == mInfoView.mAppInfoButton) {
+            mCb.onTaskAppInfoClicked(this);
+        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
new file mode 100644
index 0000000..87ebcc1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 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.systemui.settings;
+
+import com.android.systemui.R;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManagerGlobal;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * A quick and dirty view to show a user switcher.
+ */
+public class UserSwitcherHostView extends FrameLayout implements ListView.OnItemClickListener {
+
+    private static final String TAG = "UserSwitcherDialog";
+
+    private ArrayList<UserInfo> mUserInfo = new ArrayList<UserInfo>();
+    private Adapter mAdapter = new Adapter();
+    private UserManager mUserManager;
+    private Runnable mFinishRunnable;
+    private ListView mListView;
+
+    public UserSwitcherHostView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        if (isInEditMode()) {
+            return;
+        }
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+    }
+
+    public UserSwitcherHostView(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.listViewStyle);
+    }
+
+    public UserSwitcherHostView(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mListView = (ListView) findViewById(android.R.id.list);
+        mListView.setAdapter(mAdapter);
+        mListView.setOnItemClickListener(this);
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
+        int userId = mAdapter.getItem(position).id;
+        try {
+            WindowManagerGlobal.getWindowManagerService().lockNow(null);
+            ActivityManagerNative.getDefault().switchUser(userId);
+            finish();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Couldn't switch user.", e);
+        }
+    }
+
+    private void finish() {
+        if (mFinishRunnable != null) {
+            mFinishRunnable.run();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+            finish();
+        }
+        return true;
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        // A gross hack to get rid of the switcher when the shade is collapsed.
+        if (visibility != VISIBLE) {
+            finish();
+        }
+    }
+
+    public void setFinishRunnable(Runnable finishRunnable) {
+        mFinishRunnable = finishRunnable;
+    }
+
+    public void refreshUsers() {
+        mUserInfo.clear();
+        mUserInfo.addAll(mUserManager.getUsers(true));
+        mAdapter.notifyDataSetChanged();
+    }
+
+    private class Adapter extends BaseAdapter {
+
+        @Override
+        public int getCount() {
+            return mUserInfo.size();
+        }
+
+        @Override
+        public UserInfo getItem(int position) {
+            return mUserInfo.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return getItem(position).serialNumber;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null || (!(convertView.getTag() instanceof ViewHolder))) {
+                convertView = createView(parent);
+            }
+            ViewHolder h = (ViewHolder) convertView.getTag();
+            bindView(h, getItem(position));
+            return convertView;
+        }
+
+        private View createView(ViewGroup parent) {
+            View v = LayoutInflater.from(getContext()).inflate(
+                    R.layout.user_switcher_item, parent, false);
+            ViewHolder h = new ViewHolder();
+            h.name = (TextView) v.findViewById(R.id.user_name);
+            h.picture = (ImageView) v.findViewById(R.id.user_picture);
+            v.setTag(h);
+            return v;
+        }
+
+        private void bindView(ViewHolder h, UserInfo item) {
+            h.name.setText(item.name);
+            h.picture.setImageBitmap(mUserManager.getUserIcon(item.id));
+        }
+
+        class ViewHolder {
+            TextView name;
+            ImageView picture;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index f1299fe..e51b914 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -138,7 +138,8 @@
 
     protected IDreamManager mDreamManager;
     PowerManager mPowerManager;
-    protected int mRowHeight;
+    protected int mRowMinHeight;
+    protected int mRowMaxHeight;
 
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
@@ -167,9 +168,9 @@
 
     protected int mZenMode;
 
-    public IStatusBarService getStatusBarService() {
-        return mBarService;
-    }
+    protected boolean mOnKeyguard;
+    protected View mKeyguardIconOverflowContainer;
+    protected NotificationOverflowIconsView mOverflowIconsView;
 
     public boolean isDeviceProvisioned() {
         return mDeviceProvisioned;
@@ -434,8 +435,6 @@
             }
             if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
-            } else {
-                content.setBackgroundResource(com.android.internal.R.drawable.notification_bg);
             }
         }
     }
@@ -880,7 +879,7 @@
             }
         }
         entry.row = row;
-        entry.row.setRowHeight(mRowHeight);
+        entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
         entry.content = content;
         entry.expanded = contentViewLocal;
         entry.expandedPublic = publicViewLocal;
@@ -1003,7 +1002,7 @@
         // Remove the expanded view.
         ViewGroup rowParent = (ViewGroup)entry.row.getParent();
         if (rowParent != null) rowParent.removeView(entry.row);
-        updateExpansionStates();
+        updateRowStates();
         updateNotificationIcons();
 
         return entry.notification;
@@ -1046,7 +1045,7 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateExpansionStates();
+        updateRowStates();
         updateNotificationIcons();
     }
 
@@ -1054,26 +1053,53 @@
         addNotificationViews(createNotificationViews(key, notification));
     }
 
-    protected void updateExpansionStates() {
-        int N = mNotificationData.size();
-        for (int i = 0; i < N; i++) {
+    /**
+     * @return The number of notifications we show on Keyguard.
+     */
+    protected abstract int getMaxKeyguardNotifications();
+
+    /**
+     * Updates expanded, dimmed and locked states of notification rows.
+     */
+    protected void updateRowStates() {
+        int maxKeyguardNotifications = getMaxKeyguardNotifications();
+        mOverflowIconsView.removeAllViews();
+        int n = mNotificationData.size();
+        int visibleNotifications = 0;
+        for (int i = n-1; i >= 0; i--) {
             NotificationData.Entry entry = mNotificationData.get(i);
-            if (!entry.row.isUserLocked()) {
-                if (i == (N-1)) {
-                    if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
-                    entry.row.setExpanded(true);
-                } else {
-                    if (!entry.row.isUserExpanded()) {
-                        if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
-                        entry.row.setExpanded(false);
-                    } else {
-                        if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
-                    }
+            if (mOnKeyguard) {
+                entry.row.setSystemExpanded(false);
+            } else {
+                if (!entry.row.isUserLocked()) {
+                    boolean top = (i == n-1);
+                    entry.row.setSystemExpanded(top || entry.row.isUserExpanded());
+                }
+            }
+            entry.row.setDimmed(mOnKeyguard);
+            entry.row.setLocked(mOnKeyguard);
+            boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
+            if (mOnKeyguard && (visibleNotifications >= maxKeyguardNotifications
+                    || !showOnKeyguard)) {
+                entry.row.setVisibility(View.GONE);
+                if (showOnKeyguard) {
+                    mOverflowIconsView.addNotification(entry);
                 }
             } else {
-                if (DEBUG) Log.d(TAG, "ignoring notification being held by user at " + i);
+                entry.row.setVisibility(View.VISIBLE);
+                visibleNotifications++;
             }
         }
+
+        if (mOnKeyguard && mOverflowIconsView.getChildCount() > 0) {
+            mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
+        } else {
+            mKeyguardIconOverflowContainer.setVisibility(View.GONE);
+        }
+    }
+
+    private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+        return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
     }
 
     protected void setZenMode(int mode) {
@@ -1205,7 +1231,7 @@
                     handleNotificationError(key, notification, "Couldn't update icon: " + ic);
                     return;
                 }
-                updateExpansionStates();
+                updateRowStates();
             }
             catch (RuntimeException e) {
                 // It failed to add cleanly.  Log, and remove the view from the panel.
@@ -1218,13 +1244,14 @@
             if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
-            final boolean wasExpanded = oldEntry.row.isUserExpanded();
             removeNotificationViews(key);
             addNotificationViews(key, notification);  // will also replace the heads up
-            if (wasExpanded) {
-                final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
-                newEntry.row.setExpanded(true);
-                newEntry.row.setUserExpanded(true);
+            final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+            final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
+            if (userChangedExpansion) {
+                boolean userExpanded = oldEntry.row.isUserExpanded();
+                newEntry.row.applyExpansionToLayout(userExpanded);
+                newEntry.row.setUserExpanded(userExpanded);
             }
         }
 
@@ -1311,7 +1338,7 @@
         boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
                 && isAllowed
                 && mPowerManager.isScreenOn()
-                && !keyguard.isShowingAndNotHidden()
+                && !keyguard.isShowingAndNotOccluded()
                 && !keyguard.isInputRestricted();
         try {
             interrupt = interrupt && !mDreamManager.isDreaming();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 39333d7..bbbe8fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,6 +21,7 @@
 import android.os.Message;
 import android.service.notification.StatusBarNotification;
 
+import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
@@ -98,6 +99,7 @@
         public void hideSearchPanel();
         public void cancelPreloadRecentApps();
         public void setWindowState(int window, int state);
+
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -232,6 +234,7 @@
         }
     }
 
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -295,7 +298,7 @@
                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
                     break;
                 case MSG_SHOW_IME_BUTTON:
-                    mCallbacks.setImeWindowStatus((IBinder)msg.obj, msg.arg1, msg.arg2);
+                    mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2);
                     break;
                 case MSG_SET_HARD_KEYBOARD_STATUS:
                     mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
@@ -312,6 +315,7 @@
                 case MSG_SET_WINDOW_STATE:
                     mCallbacks.setWindowState(msg.arg1, msg.arg2);
                     break;
+
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b3d8688..7bacc13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -22,30 +22,53 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import com.android.internal.widget.SizeAdaptiveLayout;
 import com.android.systemui.R;
 
 public class ExpandableNotificationRow extends FrameLayout {
-    private int mRowHeight;
+    private int mRowMinHeight;
+    private int mRowMaxHeight;
 
-    /** does this row contain layouts that can adapt to row expansion */
+    /** Does this row contain layouts that can adapt to row expansion */
     private boolean mExpandable;
-    /** has the user manually expanded this row */
+    /** Has the user actively changed the expansion state of this row */
+    private boolean mHasUserChangedExpansion;
+    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
     private boolean mUserExpanded;
-    /** is the user touching this row */
+    /** Is the user touching this row */
     private boolean mUserLocked;
-    /** are we showing the "public" version */
+    /** Are we showing the "public" version */
     private boolean mShowingPublic;
 
+    private LatestItemView mLatestItemView;
+
+    /**
+     * Is this notification expanded by the system. The expansion state can be overridden by the
+     * user expansion.
+     */
+    private boolean mIsSystemExpanded;
+    private SizeAdaptiveLayout mPublicLayout;
+    private SizeAdaptiveLayout mPrivateLayout;
+    private int mMaxExpandHeight;
+    private boolean mMaxHeightNeedsUpdate;
+
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public int getRowHeight() {
-        return mRowHeight;
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic);
+        mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded);
+        mLatestItemView = (LatestItemView) findViewById(R.id.container);
     }
 
-    public void setRowHeight(int rowHeight) {
-        this.mRowHeight = rowHeight;
+
+    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
+        mRowMinHeight = rowMinHeight;
+        mRowMaxHeight = rowMaxHeight;
+        mMaxHeightNeedsUpdate = true;
     }
 
     public boolean isExpandable() {
@@ -56,11 +79,24 @@
         mExpandable = expandable;
     }
 
+    /**
+     * @return whether the user has changed the expansion state
+     */
+    public boolean hasUserChangedExpansion() {
+        return mHasUserChangedExpansion;
+    }
+
     public boolean isUserExpanded() {
         return mUserExpanded;
     }
 
+    /**
+     * Set this notification to be expanded by the user
+     *
+     * @param userExpanded whether the user wants this notification to be expanded
+     */
     public void setUserExpanded(boolean userExpanded) {
+        mHasUserChangedExpansion = true;
         mUserExpanded = userExpanded;
     }
 
@@ -72,25 +108,115 @@
         mUserLocked = userLocked;
     }
 
-    public void setExpanded(boolean expand) {
+    /**
+     * @return has the system set this notification to be expanded
+     */
+    public boolean isSystemExpanded() {
+        return mIsSystemExpanded;
+    }
+
+    /**
+     * Set this notification to be expanded by the system.
+     *
+     * @param expand whether the system wants this notification to be expanded.
+     */
+    public void setSystemExpanded(boolean expand) {
+        mIsSystemExpanded = expand;
+        applyExpansionToLayout(expand);
+    }
+
+    /**
+     * Apply an expansion state to the layout.
+     *
+     * @param expand should the layout be in the expanded state
+     */
+    public void applyExpansionToLayout(boolean expand) {
         ViewGroup.LayoutParams lp = getLayoutParams();
         if (expand && mExpandable) {
             lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
         } else {
-            lp.height = mRowHeight;
+            lp.height = mRowMinHeight;
         }
         setLayoutParams(lp);
     }
 
+    /**
+     * If {@link #isExpanded()} then this is the greatest possible height this view can
+     * get and otherwise it is {@link #mRowMinHeight}.
+     *
+     * @return the maximum allowed expansion height of this view.
+     */
+    public int getMaximumAllowedExpandHeight() {
+        boolean inExpansionState = isExpanded();
+        if (!inExpansionState) {
+            // not expanded, so we return the collapsed size
+            return mRowMinHeight;
+        }
+
+        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
+    }
+
+    private void updateMaxExpandHeight() {
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        int oldHeight = lp.height;
+        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        setLayoutParams(lp);
+        measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST));
+        lp.height = oldHeight;
+        setLayoutParams(lp);
+        mMaxExpandHeight = getMeasuredHeight();
+    }
+
+    /**
+     * Check whether the view state is currently expanded. This is given by the system in {@link
+     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
+     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
+     * view can differ from this state, if layout params are modified from outside.
+     *
+     * @return whether the view state is currently expanded.
+     */
+    private boolean isExpanded() {
+        return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mMaxHeightNeedsUpdate = true;
+    }
+
     public void setShowingPublic(boolean show) {
         mShowingPublic = show;
-        final ViewGroup publicLayout = (ViewGroup) findViewById(R.id.expandedPublic);
 
         // bail out if no public version
-        if (publicLayout.getChildCount() == 0) return;
+        if (mPublicLayout.getChildCount() == 0) return;
 
         // TODO: animation?
-        publicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
-        findViewById(R.id.expanded).setVisibility(show ? View.GONE : View.VISIBLE);
+        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
+        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
+    }
+
+    /**
+     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
+     */
+    public void setDimmed(boolean dimmed) {
+        mLatestItemView.setDimmed(dimmed);
+    }
+
+    public int getMaxExpandHeight() {
+        if (mMaxHeightNeedsUpdate) {
+            updateMaxExpandHeight();
+            mMaxHeightNeedsUpdate = false;
+        }
+        return mMaxExpandHeight;
+    }
+
+    /**
+     * Sets the notification as locked. In the locked state, the first tap will produce a quantum
+     * ripple to make the notification brighter and only the second tap will cause a click.
+     */
+    public void setLocked(boolean locked) {
+        mLatestItemView.setLocked(locked);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
index 6419777..ad9028d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
@@ -17,16 +17,44 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
 public class LatestItemView extends FrameLayout {
+
+    private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+
+    private boolean mDimmed;
+    private boolean mLocked;
+
+    /**
+     * Flag to indicate that the notification has been touched once and the second touch will
+     * click it.
+     */
+    private boolean mActivated;
+
+    private float mDownX;
+    private float mDownY;
+    private final float mTouchSlop;
+    private boolean mHotspotActive;
+
     public LatestItemView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
+    private final Runnable mTapTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            makeInactive();
+        }
+    };
+
     @Override
     public void setOnClickListener(OnClickListener l) {
         super.setOnClickListener(l);
@@ -45,4 +73,94 @@
         }
         return false;
     }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mLocked) {
+            return handleTouchEventLocked(event);
+        } else {
+            return super.onTouchEvent(event);
+        }
+    }
+
+    private boolean handleTouchEventLocked(MotionEvent event) {
+        int action = event.getActionMasked();
+        Drawable background = getBackground();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mDownX = event.getX();
+                mDownY = event.getY();
+                if (!mActivated) {
+                    background.setHotspot(0, event.getX(), event.getY());
+                    mHotspotActive = true;
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (!isWithinTouchSlop(event)) {
+                    makeInactive();
+                    return false;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (isWithinTouchSlop(event)) {
+                    if (!mActivated) {
+                        mActivated = true;
+                        postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
+                    } else {
+                        performClick();
+                        makeInactive();
+                    }
+                } else {
+                    makeInactive();
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                makeInactive();
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+
+    /**
+     * Cancels the hotspot and makes the notification inactive.
+     */
+    private void makeInactive() {
+        if (mHotspotActive) {
+            // Make sure that we clear the hotspot from the center.
+            getBackground().setHotspot(0, getWidth()/2, getHeight()/2);
+            getBackground().removeHotspot(0);
+            mHotspotActive = false;
+        }
+        mActivated = false;
+        removeCallbacks(mTapTimeoutRunnable);
+    }
+
+    private boolean isWithinTouchSlop(MotionEvent event) {
+        return Math.abs(event.getX() - mDownX) < mTouchSlop
+                && Math.abs(event.getY() - mDownY) < mTouchSlop;
+    }
+
+    /**
+     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
+     */
+    public void setDimmed(boolean dimmed) {
+        if (mDimmed != dimmed) {
+            mDimmed = dimmed;
+            if (dimmed) {
+                setBackgroundResource(com.android.internal.R.drawable.notification_quantum_bg_dim);
+            } else {
+                setBackgroundResource(com.android.internal.R.drawable.notification_quantum_bg);
+            }
+        }
+    }
+
+    /**
+     * Sets the notification as locked. In the locked state, the first tap will produce a quantum
+     * ripple to make the notification brighter and only the second tap will cause a click.
+     */
+    public void setLocked(boolean locked) {
+        mLocked = locked;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
new file mode 100644
index 0000000..ce31894
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 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.systemui.statusbar;
+
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.IconMerger;
+
+/**
+ * A view to display all the overflowing icons on Keyguard.
+ */
+public class NotificationOverflowIconsView extends IconMerger {
+
+    private TextView mMoreText;
+    private int mTintColor;
+
+    public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color);
+    }
+
+    public void setMoreText(TextView moreText) {
+        mMoreText = moreText;
+    }
+
+    public void addNotification(NotificationData.Entry notification) {
+        StatusBarIconView v = new StatusBarIconView(getContext(), "",
+                notification.notification.getNotification());
+        v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        v.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
+        addView(v);
+        v.set(notification.icon.getStatusBarIcon());
+        updateMoreText();
+    }
+
+    private void updateMoreText() {
+        mMoreText.setText(getResources().getQuantityString(
+                R.plurals.keyguard_more_overflow_text, getChildCount(), getChildCount()));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
new file mode 100644
index 0000000..7cbde36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardViewBase;
+import com.android.keyguard.R;
+import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+
+/**
+ * A class which manages the bouncer on the lockscreen.
+ */
+public class KeyguardBouncer {
+
+    private Context mContext;
+    private ViewMediatorCallback mCallback;
+    private LockPatternUtils mLockPatternUtils;
+    private ViewGroup mContainer;
+    private StatusBarWindowManager mWindowManager;
+    private KeyguardViewBase mKeyguardView;
+    private ViewGroup mRoot;
+
+    public KeyguardBouncer(Context context, ViewMediatorCallback callback,
+            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
+            ViewGroup container) {
+        mContext = context;
+        mCallback = callback;
+        mLockPatternUtils = lockPatternUtils;
+        mContainer = container;
+        mWindowManager = windowManager;
+    }
+
+    public void prepare() {
+        ensureView();
+    }
+
+    public void show() {
+        ensureView();
+
+        // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
+        // Keyguard. If we need to authenticate, show the bouncer.
+        if (!mKeyguardView.dismiss()) {
+            mRoot.setVisibility(View.VISIBLE);
+            mKeyguardView.requestFocus();
+        }
+    }
+
+    public void hide() {
+        if (mKeyguardView != null) {
+            mKeyguardView.cleanUp();
+        }
+        removeView();
+    }
+
+    /**
+     * Reset the state of the view.
+     */
+    public void reset() {
+        inflateView();
+    }
+
+    public void onScreenTurnedOff() {
+        if (mKeyguardView != null) {
+            mKeyguardView.onScreenTurnedOff();
+        }
+    }
+
+    public void onScreenTurnedOn() {
+        if (mKeyguardView != null) {
+            mKeyguardView.onScreenTurnedOn();
+        }
+    }
+
+    public long getUserActivityTimeout() {
+        if (mKeyguardView != null) {
+            long timeout = mKeyguardView.getUserActivityTimeout();
+            if (timeout >= 0) {
+                return timeout;
+            }
+        }
+        return KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
+    }
+
+    public boolean isShowing() {
+        return mRoot != null && mRoot.getVisibility() == View.VISIBLE;
+    }
+
+    private void ensureView() {
+        if (mRoot == null) {
+            inflateView();
+        }
+    }
+
+    private void inflateView() {
+        removeView();
+        mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
+        mKeyguardView = (KeyguardViewBase) mRoot.findViewById(R.id.keyguard_host_view);
+        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
+        mKeyguardView.setViewMediatorCallback(mCallback);
+        mContainer.addView(mRoot, mContainer.getChildCount());
+        mRoot.setVisibility(View.INVISIBLE);
+        mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
+    }
+
+    private void removeView() {
+        if (mRoot != null && mRoot.getParent() == mContainer) {
+            mContainer.removeView(mRoot);
+            mRoot = null;
+        }
+    }
+
+    public boolean onBackPressed() {
+        return mKeyguardView != null && mKeyguardView.handleBackKey();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
index 1ea920d..754075a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -39,8 +39,8 @@
  */
 public class KeyguardTouchDelegate {
     // TODO: propagate changes to these to {@link KeyguardServiceDelegate}
-    static final String KEYGUARD_PACKAGE = "com.android.keyguard";
-    static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+    static final String KEYGUARD_PACKAGE = "com.android.systemui";
+    static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";
 
     private static KeyguardTouchDelegate sInstance;
     private static final List<OnKeyguardConnectionListener> sConnectionListeners =
@@ -140,16 +140,16 @@
         return false;
     }
 
-    public boolean isShowingAndNotHidden() {
+    public boolean isShowingAndNotOccluded() {
         final IKeyguardService service = mService;
         if (service != null) {
             try {
-                return service.isShowingAndNotHidden();
+                return service.isShowingAndNotOccluded();
             } catch (RemoteException e) {
                 Slog.w(TAG , "Remote Exception", e);
             }
         } else {
-            Slog.w(TAG, "isShowingAndNotHidden(): NO SERVICE!");
+            Slog.w(TAG, "isShowingAndNotOccluded(): NO SERVICE!");
         }
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index a74230b..d26b32f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -117,7 +117,7 @@
     @Override
     public void setContentVisible(boolean visible) {
         final float alpha = visible ? 1 : 0;
-        fadeContent(mView.getCameraButton(), alpha);
+        fadeContent(mView.getBackButton(), alpha);
         fadeContent(mView.getSearchLight(), alpha);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d9e0903..db26a42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -34,17 +34,23 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.MediaStore;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Display;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -92,12 +98,16 @@
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
     final static int MSG_CHECK_INVALID_LAYOUT = 8686;
 
+    private final float mCameraDragDistance;
+
     // used to disable the camera icon in navbar when disabled by DPM
     private boolean mCameraDisabledByDpm;
 
     // performs manual animation in sync with layout transitions
     private final NavTransitionListener mTransitionListener = new NavTransitionListener();
 
+    private final PowerManager mPowerManager;
+
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
         private boolean mHomeAppearing;
@@ -155,22 +165,73 @@
         }
     };
 
+    private final int mScaledTouchSlop;
+
     private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
+        private float mStartX;
+        private boolean mTouchSlopReached;
+        private boolean mSkipCancelAnimation;
+
         @Override
-        public boolean onTouch(View cameraButtonView, MotionEvent event) {
+        public boolean onTouch(final View cameraButtonView, MotionEvent event) {
+            float realX = event.getRawX();
             switch (event.getAction()) {
                 case MotionEvent.ACTION_DOWN:
                     // disable search gesture while interacting with camera
                     mDelegateHelper.setDisabled(true);
                     mBarTransitions.setContentVisible(false);
+                    mStartX = realX;
+                    mTouchSlopReached = false;
+                    mSkipCancelAnimation = false;
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    if (realX > mStartX) {
+                        realX = mStartX;
+                    }
+                    if (realX < mStartX - mCameraDragDistance) {
+                        ((KeyButtonView) cameraButtonView).setPressed(true);
+                        mPowerManager.userActivity(event.getEventTime(), false);
+                    } else {
+                        ((KeyButtonView) cameraButtonView).setPressed(false);
+                    }
+                    if (realX < mStartX - mScaledTouchSlop) {
+                        mTouchSlopReached = true;
+                    }
+                    cameraButtonView.setTranslationX(Math.max(realX - mStartX,
+                            -mCameraDragDistance));
                     break;
                 case MotionEvent.ACTION_UP:
+                    if (realX < mStartX - mCameraDragDistance) {
+                        mContext.startActivityAsUser(
+                                new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
+                                UserHandle.CURRENT);
+                    }
+                    if (realX < mStartX - mScaledTouchSlop) {
+                        mTouchSlopReached = true;
+                    }
+                    if (!mTouchSlopReached) {
+                        mSkipCancelAnimation = true;
+                        cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
+                                        setInterpolator(new DecelerateInterpolator()).withEndAction(
+                                new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        cameraButtonView.animate().translationX(0).
+                                                setInterpolator(new AccelerateInterpolator());
+                                    }
+                                });
+                    }
                 case MotionEvent.ACTION_CANCEL:
+                    ((KeyButtonView) cameraButtonView).setPressed(false);
                     mDelegateHelper.setDisabled(false);
                     mBarTransitions.setContentVisible(true);
+                    if (!mSkipCancelAnimation) {
+                        cameraButtonView.animate().translationX(0)
+                                .setInterpolator(new AccelerateInterpolator(2f));
+                    }
                     break;
             }
-            return KeyguardTouchDelegate.getInstance(getContext()).dispatch(event);
+            return true;
         }
     };
 
@@ -235,6 +296,9 @@
         KeyguardTouchDelegate.addListener(mKeyguardConnectionListener);
         mCameraDisabledByDpm = isCameraDisabledByDpm();
         watchForDevicePolicyChanges();
+        mCameraDragDistance = res.getDimension(R.dimen.camera_drag_distance);
+        mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
 
     private void watchForDevicePolicyChanges() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2d2f2f1..6f93bed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -139,6 +139,7 @@
      * @param expandedHeight the new expanded height
      */
     private void updateNotificationStackHeight(float expandedHeight) {
+        mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f);
         float childOffset = getRelativeTop(mNotificationStackScroller)
                 - mNotificationParent.getTranslationY();
         int newStackHeight = (int) (expandedHeight - childOffset);
@@ -168,4 +169,16 @@
     protected int getDesiredMeasureHeight() {
         return mMaxPanelHeight;
     }
+
+    @Override
+    protected void onExpandingStarted() {
+        super.onExpandingStarted();
+        mNotificationStackScroller.onExpansionStarted();
+    }
+
+    @Override
+    protected void onExpandingFinished() {
+        super.onExpandingFinished();
+        mNotificationStackScroller.onExpansionStopped();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index a3e35d1..324d6f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -151,7 +151,8 @@
         if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
         mPanelExpandedFractionSum = 0f;
         for (PanelView pv : mPanels) {
-            final boolean visible = pv.getVisibility() == View.VISIBLE;
+            boolean visible = pv.getExpandedHeight() > 0;
+            pv.setVisibility(visible ? View.VISIBLE : View.GONE);
             // adjust any other panels that may be partially visible
             if (pv.getExpandedHeight() > 0f) {
                 if (mState == STATE_CLOSED) {
@@ -166,11 +167,6 @@
                     if (thisFrac == 1f) fullyOpenedPanel = panel;
                 }
             }
-            if (pv.getExpandedHeight() > 0f) {
-                if (!visible) pv.setVisibility(View.VISIBLE);
-            } else {
-                if (visible) pv.setVisibility(View.GONE);
-            }
         }
         mPanelExpandedFractionSum /= mPanels.size();
         if (fullyOpenedPanel != null && !mTracking) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 20fb225..10a9b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -216,6 +216,7 @@
                 mTimeAnimator.end();
                 mRubberbanding = false;
                 mClosing = false;
+                onExpandingFinished();
             }
         }
     };
@@ -230,6 +231,12 @@
         mRubberbandingEnabled = enable;
     }
 
+    protected void onExpandingFinished() {
+    }
+
+    protected void onExpandingStarted() {
+    }
+
     private void runPeekAnimation() {
         if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
         if (mTimeAnimator.isStarted()) {
@@ -398,7 +405,7 @@
                 initVelocityTracker();
                 trackMovement(event);
                 mTimeAnimator.cancel(); // end any outstanding animations
-                mBar.onTrackingStarted(PanelView.this);
+                onTrackingStarted();
                 mInitialOffsetOnTouch = mExpandedHeight;
                 if (mExpandedHeight == 0) {
                     mJustPeeked = true;
@@ -443,7 +450,7 @@
                     mHandleView.setPressed(false);
                     postInvalidate(); // catch the press state change
                 }
-                mBar.onTrackingStopped(PanelView.this);
+                onTrackingStopped();
                 trackMovement(event);
 
                 float vel = getCurrentVelocity();
@@ -458,6 +465,15 @@
         return true;
     }
 
+    protected void onTrackingStopped() {
+        mBar.onTrackingStopped(PanelView.this);
+    }
+
+    protected void onTrackingStarted() {
+        mBar.onTrackingStarted(PanelView.this);
+        onExpandingStarted();
+    }
+
     private float getCurrentVelocity() {
         float vel = 0;
         float yVel = 0, xVel = 0;
@@ -561,6 +577,7 @@
                         mInitialOffsetOnTouch = mExpandedHeight;
                         mInitialTouchY = y;
                         mTracking = true;
+                        onTrackingStarted();
                         return true;
                     }
                 }
@@ -598,6 +615,8 @@
 
         if (always||mVel != 0) {
             animationTick(0); // begin the animation
+        } else {
+            onExpandingFinished();
         }
     }
 
@@ -632,6 +651,12 @@
         int newHeight = getMeasuredHeight();
         if (newHeight != mMaxPanelHeight) {
             mMaxPanelHeight = newHeight;
+            // If the user isn't actively poking us, let's rubberband to the content
+            if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
+                    && mExpandedHeight > 0 && mExpandedHeight != mMaxPanelHeight
+                    && mMaxPanelHeight > 0) {
+                mExpandedHeight = mMaxPanelHeight;
+            }
         }
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                     getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
@@ -770,6 +795,7 @@
         if (!isFullyCollapsed()) {
             mTimeAnimator.cancel();
             mClosing = true;
+            onExpandingStarted();
             // collapse() should never be a rubberband, even if an animation is already running
             mRubberbanding = false;
             fling(-mSelfCollapseVelocityPx, /*always=*/ true);
@@ -780,6 +806,7 @@
         if (DEBUG) logf("expand: " + this);
         if (isFullyCollapsed()) {
             mBar.startOpeningPanel(this);
+            onExpandingStarted();
             fling(mSelfExpandVelocityPx, /*always=*/ true);
         } else if (DEBUG) {
             if (DEBUG) logf("skipping expansion: is expanded");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f3dd7e3..ec9f3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,14 +16,16 @@
 
 package com.android.systemui.statusbar.phone;
 
+
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
+import static com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -66,6 +68,7 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -84,15 +87,19 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.InterceptedNotifications;
+import com.android.systemui.statusbar.LatestItemView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
+import com.android.systemui.statusbar.NotificationOverflowIconsView;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -174,6 +181,7 @@
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
+    private StatusBarWindowManager mStatusBarWindowManager;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
@@ -212,9 +220,12 @@
 
     // top bar
     View mNotificationPanelHeader;
+    View mKeyguardStatusView;
+    int mKeyguardMaxNotificationCount;
     View mDateTimeView;
     View mClearButton;
     ImageView mSettingsButton, mNotificationButton;
+    View mKeyguardSettingsFlipButton;
 
     // carrier/wifi label
     private TextView mCarrierLabel;
@@ -337,6 +348,9 @@
     private int mNavigationBarMode;
     private Boolean mScreenOn;
 
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private ViewMediatorCallback mKeyguardViewMediatorCallback;
+
     private final Runnable mAutohide = new Runnable() {
         @Override
         public void run() {
@@ -349,6 +363,14 @@
     private Runnable mOnFlipRunnable;
     private InterceptedNotifications mIntercepted;
 
+    private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
+            new OnChildLocationsChangedListener() {
+        @Override
+        public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout) {
+            userActivity();
+        }
+    };
+
     public void setOnFlipRunnable(Runnable onFlipRunnable) {
         mOnFlipRunnable = onFlipRunnable;
     }
@@ -388,6 +410,7 @@
                     Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                     mHeadsUpObserver);
         }
+        startKeyguard();
     }
 
     // ================================================================================
@@ -494,10 +517,21 @@
         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                 R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
+        mStackScroller.setChildLocationsChangedListener(mOnChildLocationsChangedListener);
+
+        mKeyguardIconOverflowContainer = LayoutInflater.from(mContext).inflate(
+                R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
+        ((LatestItemView) mKeyguardIconOverflowContainer.findViewById(R.id.container)).setLocked(true);
+        mOverflowIconsView = (NotificationOverflowIconsView) mKeyguardIconOverflowContainer.findViewById(
+                R.id.overflow_icons_view);
+        mOverflowIconsView.setMoreText(
+                (TextView) mKeyguardIconOverflowContainer.findViewById(R.id.more_text));
+        mStackScroller.addView(mKeyguardIconOverflowContainer);
 
         mExpandedContents = mStackScroller;
 
         mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
+        mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
 
         mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
         mClearButton.setOnClickListener(mClearButtonListener);
@@ -687,6 +721,13 @@
         return mStatusBarView;
     }
 
+    private void startKeyguard() {
+        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
+        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
+                mStatusBarWindow, mStatusBarWindowManager);
+        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
+    }
+
     @Override
     protected void onShowSearchPanel() {
         if (mNavigationBarView != null) {
@@ -764,10 +805,6 @@
         }
     }
 
-    protected int getStatusBarGravity() {
-        return Gravity.TOP | Gravity.FILL_HORIZONTAL;
-    }
-
     public int getStatusBarHeight() {
         if (mNaturalBarHeight < 0) {
             final Resources res = mContext.getResources();
@@ -1024,7 +1061,7 @@
             }
 
             if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
-                    && !mNotificationPanel.isTracking()) {
+                    && !mNotificationPanel.isTracking() && !mOnKeyguard) {
                 animateCollapsePanels();
             }
         }
@@ -1093,7 +1130,7 @@
         ArrayList<View> toRemove = new ArrayList<View>();
         for (int i=0; i< mStackScroller.getChildCount(); i++) {
             View child = mStackScroller.getChildAt(i);
-            if (!toShow.contains(child)) {
+            if (!toShow.contains(child) && child != mKeyguardIconOverflowContainer) {
                 toRemove.add(child);
             }
         }
@@ -1493,26 +1530,13 @@
 
         // Expand the window to encompass the full screen in anticipation of the drag.
         // This is only possible to do atomically because the status bar is at the top of the screen!
-        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
-        lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
-        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
+        mStatusBarWindowManager.setStatusBarExpanded(true);
 
         visibilityChanged(true);
 
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
     }
 
-    private void releaseFocus() {
-        if (mStatusBarWindow == null) return;
-        WindowManager.LayoutParams lp =
-                (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
-        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
-    }
-
     public void animateCollapsePanels() {
         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
     }
@@ -1524,9 +1548,6 @@
                     + " flags=" + flags);
         }
 
-        // release focus immediately to kick off focus change transition
-        releaseFocus();
-
         if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
             mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
             mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
@@ -1538,6 +1559,10 @@
         }
 
         if (mStatusBarWindow != null) {
+
+            // release focus immediately to kick off focus change transition
+            mStatusBarWindowManager.setStatusBarFocusable(false);
+
             mStatusBarWindow.cancelExpandHelper();
             mStatusBarView.collapseAllPanels(true);
         }
@@ -1796,11 +1821,7 @@
         visibilityChanged(false);
 
         // Shrink the window to the size of the status bar only
-        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
-        lp.height = getStatusBarHeight();
-        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-        lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
+        mStatusBarWindowManager.setStatusBarExpanded(false);
 
         if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
             setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
@@ -1815,6 +1836,8 @@
         }
 
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
+
+        showBouncer();
     }
 
     public boolean interceptTouchEvent(MotionEvent event) {
@@ -2303,30 +2326,9 @@
     }
 
     private void addStatusBarWindow() {
-        // Put up the view
-        final int height = getStatusBarHeight();
-
-        // Now that the status bar window encompasses the sliding panel and its
-        // translucent backdrop, the entire thing is made TRANSLUCENT and is
-        // hardware-accelerated.
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                height,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
-                PixelFormat.TRANSLUCENT);
-
-        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-
-        lp.gravity = getStatusBarGravity();
-        lp.setTitle("StatusBar");
-        lp.packageName = mContext.getPackageName();
-
         makeStatusBarView();
-        mWindowManager.addView(mStatusBarWindow, lp);
+        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
+        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
     }
 
     void setNotificationIconVisibility(boolean visible, int anim) {
@@ -2464,8 +2466,6 @@
             }
             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 mScreenOn = false;
-                // no waiting!
-                makeExpandedInvisible();
                 notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOn(false);
                 finishBarAnimations();
@@ -2641,7 +2641,10 @@
         }
 
         mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
-        mRowHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+        mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+        mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_row_max_height);
+
+        mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count);
 
         if (false) Log.v(TAG, "updateResources");
     }
@@ -2814,4 +2817,120 @@
             ((DemoMode)v).dispatchDemoCommand(command, args);
         }
     }
+
+    public boolean isOnKeyguard() {
+        return mOnKeyguard;
+    }
+
+    public void showKeyguard() {
+        mOnKeyguard = true;
+        instantExpandNotificationsPanel();
+        if (isFlippedToSettings()) {
+            flipToNotifications();
+        }
+        mStatusBarWindow.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
+        mKeyguardStatusView.setVisibility(View.VISIBLE);
+        mNotificationPanelHeader.setVisibility(View.GONE);
+        if (mKeyguardSettingsFlipButton == null) {
+            ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub);
+            mKeyguardSettingsFlipButton = flipStub.inflate();
+            installSettingsButton(mKeyguardSettingsFlipButton);
+        }
+        mKeyguardSettingsFlipButton.setVisibility(View.VISIBLE);
+        mKeyguardSettingsFlipButton.findViewById(R.id.settings_button).setVisibility(View.VISIBLE);
+        mKeyguardSettingsFlipButton.findViewById(R.id.notification_button)
+                .setVisibility(View.INVISIBLE);
+        updateRowStates();
+    }
+
+    public void hideKeyguard() {
+        mOnKeyguard = false;
+        mStatusBarWindow.setSystemUiVisibility(0);
+        mKeyguardStatusView.setVisibility(View.GONE);
+        mNotificationPanelHeader.setVisibility(View.VISIBLE);
+        mKeyguardSettingsFlipButton.setVisibility(View.GONE);
+        updateRowStates();
+    }
+
+    public void userActivity() {
+        if (mOnKeyguard) {
+            mKeyguardViewMediatorCallback.userActivity();
+        }
+    }
+
+    public boolean onBackPressed() {
+        if (mOnKeyguard) {
+            return mStatusBarKeyguardViewManager.onBackPressed();
+        } else {
+            animateCollapsePanels();
+            return true;
+        }
+    }
+
+    private void showBouncer() {
+        if (mOnKeyguard) {
+            mStatusBarKeyguardViewManager.dismiss();
+        }
+    }
+
+    private void instantExpandNotificationsPanel() {
+        mExpandedVisible = true;
+        mNotificationPanel.setExpandedFraction(1);
+    }
+
+    @Override
+    protected int getMaxKeyguardNotifications() {
+        return mKeyguardMaxNotificationCount;
+    }
+
+    /**
+     * @return a ViewGroup that spans the entire panel which contains the quick settings
+     */
+    public ViewGroup getQuickSettingsOverlayParent() {
+        if (mHasSettingsPanel) {
+            if (mHasFlipSettings) {
+                return mNotificationPanel;
+            } else {
+                return mSettingsPanel;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private void installSettingsButton(View parent) {
+        final ImageView settingsButton =
+                (ImageView) mStatusBarWindow.findViewById(R.id.settings_button);
+        final ImageView notificationButton =
+                (ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
+        if (settingsButton != null) {
+            settingsButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    animateExpandSettingsPanel();
+                    v.setVisibility(View.INVISIBLE);
+                    notificationButton.setVisibility(View.VISIBLE);
+                }
+            });
+            settingsButton.setVisibility(View.VISIBLE);
+            if (mHasSettingsPanel) {
+                // the settings panel is hiding behind this button
+                settingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
+            } else {
+                // no settings panel, go straight to settings
+                settingsButton.setImageResource(R.drawable.ic_notify_settings);
+            }
+        }
+        if (notificationButton != null) {
+            notificationButton.setVisibility(View.INVISIBLE);
+            notificationButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    flipToNotifications();
+                    v.setVisibility(View.INVISIBLE);
+                    settingsButton.setVisibility(View.VISIBLE);
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index d9e3fdf..583fc3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -37,6 +37,7 @@
 
     PhoneStatusBar mBar;
     int mScrimColor;
+    int mScrimColorKeyguard;
     float mSettingsPanelDragzoneFrac;
     float mSettingsPanelDragzoneMin;
 
@@ -52,6 +53,7 @@
 
         Resources res = getContext().getResources();
         mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
+        mScrimColorKeyguard = res.getColor(R.color.notification_panel_scrim_color_keyguard);
         mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min);
         try {
             mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1);
@@ -217,6 +219,7 @@
         if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
                 && mBar.mStatusBarWindow != null) {
             if (mShouldFade) {
+                int scrimColor = mBar.isOnKeyguard() ? mScrimColorKeyguard : mScrimColor;
                 frac = mPanelExpandedFractionSum; // don't judge me
                 // let's start this 20% of the way down the screen
                 frac = frac * 1.2f - 0.2f;
@@ -226,7 +229,7 @@
                     // woo, special effects
                     final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
                     // attenuate background color alpha by k
-                    final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
+                    final int color = (int) ((scrimColor >>> 24) * k) << 24 | (scrimColor & 0xFFFFFF);
                     mBar.mStatusBarWindow.setBackgroundColor(color);
                 }
             }
@@ -249,5 +252,6 @@
         mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
 
         mBar.updateCarrierLabelVisibility(false);
+        mBar.userActivity();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index d67f7cd..b3fba76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -71,6 +71,7 @@
 
 import com.android.internal.app.MediaRouteDialogPresenter;
 import com.android.systemui.R;
+import com.android.systemui.settings.UserSwitcherHostView;
 import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
 import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
 import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
@@ -310,30 +311,28 @@
         collapsePanels();
     }
 
-    private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
+    private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) {
         QuickSettingsTileView userTile = (QuickSettingsTileView)
                 inflater.inflate(R.layout.quick_settings_tile, parent, false);
         userTile.setContent(R.layout.quick_settings_tile_user, inflater);
         userTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                collapsePanels();
                 final UserManager um = UserManager.get(mContext);
                 if (um.isUserSwitcherEnabled()) {
-                    // Since keyguard and systemui were merged into the same process to save
-                    // memory, they share the same Looper and graphics context.  As a result,
-                    // there's no way to allow concurrent animation while keyguard inflates.
-                    // The workaround is to add a slight delay to allow the animation to finish.
-                    mHandler.postDelayed(new Runnable() {
+                    final ViewGroup switcherParent = getService().getQuickSettingsOverlayParent();
+                    final UserSwitcherHostView switcher = (UserSwitcherHostView) inflater.inflate(
+                            R.layout.user_switcher_host, switcherParent, false);
+                    switcher.setFinishRunnable(new Runnable() {
+                        @Override
                         public void run() {
-                            try {
-                                WindowManagerGlobal.getWindowManagerService().lockNow(null);
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Couldn't show user switcher", e);
-                            }
+                            switcherParent.removeView(switcher);
                         }
-                    }, 400); // TODO: ideally this would be tied to the collapse of the panel
+                    });
+                    switcher.refreshUsers();
+                    switcherParent.addView(switcher);
                 } else {
+                    collapsePanels();
                     Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                             mContext, v, ContactsContract.Profile.CONTENT_URI,
                             ContactsContract.QuickContact.MODE_LARGE, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
new file mode 100644
index 0000000..b8592c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardSimpleHostView;
+import com.android.keyguard.R;
+import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+
+/**
+ * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
+ * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
+ * which is in turn, reported to this class by the current
+ * {@link com.android.keyguard.KeyguardViewBase}.
+ */
+public class StatusBarKeyguardViewManager {
+    private static String TAG = "StatusBarKeyguardViewManager";
+
+    private final Context mContext;
+
+    private LockPatternUtils mLockPatternUtils;
+    private ViewMediatorCallback mViewMediatorCallback;
+    private PhoneStatusBar mPhoneStatusBar;
+
+    private ViewGroup mContainer;
+    private StatusBarWindowManager mStatusBarWindowManager;
+
+    private boolean mScreenOn = false;
+    private KeyguardBouncer mBouncer;
+    private boolean mShowing;
+
+    public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
+            LockPatternUtils lockPatternUtils) {
+        mContext = context;
+        mViewMediatorCallback = callback;
+        mLockPatternUtils = lockPatternUtils;
+    }
+
+    public void registerStatusBar(PhoneStatusBar phoneStatusBar,
+            ViewGroup container, StatusBarWindowManager statusBarWindowManager) {
+        mPhoneStatusBar = phoneStatusBar;
+        mContainer = container;
+        mStatusBarWindowManager = statusBarWindowManager;
+        mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
+                mStatusBarWindowManager, container);
+    }
+
+    /**
+     * Show the keyguard.  Will handle creating and attaching to the view manager
+     * lazily.
+     */
+    public void show(Bundle options) {
+        mShowing = true;
+        mStatusBarWindowManager.setKeyguardShowing(true);
+        mPhoneStatusBar.showKeyguard();
+        mBouncer.prepare();
+        updateBackButtonState();
+    }
+
+    public void showBouncer() {
+        mBouncer.show();
+        updateBackButtonState();
+    }
+
+    /**
+     * Reset the state of the view.
+     */
+    public void reset() {
+        mBouncer.reset();
+        mPhoneStatusBar.showKeyguard();
+        updateBackButtonState();
+    }
+
+    public void onScreenTurnedOff() {
+        mScreenOn = false;
+        mBouncer.onScreenTurnedOff();
+    }
+
+    public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
+        mScreenOn = true;
+        mBouncer.onScreenTurnedOn();
+        if (callback != null) {
+            callbackAfterDraw(callback);
+        }
+    }
+
+    private void callbackAfterDraw(final IKeyguardShowCallback callback) {
+        mContainer.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    callback.onShown(mContainer.getWindowToken());
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception calling onShown():", e);
+                }
+            }
+        });
+    }
+
+    public void verifyUnlock() {
+        dismiss();
+    }
+
+    public void setNeedsInput(boolean needsInput) {
+        mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
+    }
+
+    public void updateUserActivityTimeout() {
+        mStatusBarWindowManager.setKeyguardUserActivityTimeout(mBouncer.getUserActivityTimeout());
+    }
+
+    public void setOccluded(boolean occluded) {
+        mStatusBarWindowManager.setKeyguardOccluded(occluded);
+    }
+
+    /**
+     * Hides the keyguard view
+     */
+    public void hide() {
+        mShowing = false;
+        mPhoneStatusBar.hideKeyguard();
+        mStatusBarWindowManager.setKeyguardShowing(false);
+        mBouncer.hide();
+        mViewMediatorCallback.keyguardGone();
+    }
+
+    /**
+     * Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public void dismiss() {
+        if (mScreenOn) {
+            showBouncer();
+        }
+    }
+
+    /**
+     * @return Whether the keyguard is showing
+     */
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    /**
+     * Notifies this manager that the back button has been pressed.
+     *
+     * @return whether the back press has been handled
+     */
+    public boolean onBackPressed() {
+        if (mBouncer.isShowing()) {
+            mBouncer.hide();
+            mPhoneStatusBar.showKeyguard();
+            updateBackButtonState();
+            return true;
+        }
+        return false;
+    }
+
+    private void updateBackButtonState() {
+        int vis = mContainer.getSystemUiVisibility();
+        if (mBouncer.isShowing()) {
+            mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
+        } else {
+            mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
new file mode 100644
index 0000000..6153cde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2014 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.systemui.statusbar.phone;
+
+import android.app.ActionBar;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.SystemProperties;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.keyguard.R;
+
+/**
+ * Encapsulates all logic for the status bar window state management.
+ */
+public class StatusBarWindowManager {
+
+    private final Context mContext;
+    private final WindowManager mWindowManager;
+    private View mStatusBarView;
+    private WindowManager.LayoutParams mLp;
+    private int mBarHeight;
+    private final boolean mKeyguardScreenRotation;
+
+    private final State mCurrentState = new State();
+
+    public StatusBarWindowManager(Context context) {
+        mContext = context;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
+    }
+
+    private boolean shouldEnableKeyguardScreenRotation() {
+        Resources res = mContext.getResources();
+        return SystemProperties.getBoolean("lockscreen.rot_override", false)
+                || res.getBoolean(R.bool.config_enableLockScreenRotation);
+    }
+
+    /**
+     * Adds the status bar view to the window manager.
+     *
+     * @param statusBarView The view to add.
+     * @param barHeight The height of the status bar in collapsed state.
+     */
+    public void add(View statusBarView, int barHeight) {
+
+        // Now that the status bar window encompasses the sliding panel and its
+        // translucent backdrop, the entire thing is made TRANSLUCENT and is
+        // hardware-accelerated.
+        mLp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                barHeight,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
+                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
+                PixelFormat.TRANSLUCENT);
+
+        mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        mLp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        mLp.setTitle("StatusBar");
+        mLp.packageName = mContext.getPackageName();
+        mStatusBarView = statusBarView;
+        mBarHeight = barHeight;
+        mWindowManager.addView(mStatusBarView, mLp);
+    }
+
+    private void applyKeyguardFlags(State state) {
+        if (state.keyguardShowing) {
+            mLp.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+        } else {
+            mLp.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+            mLp.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+        }
+    }
+
+    private void adjustScreenOrientation(State state) {
+        if (!state.isKeyguardShowingAndNotOccluded() || mKeyguardScreenRotation) {
+            mLp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
+        } else {
+            mLp.screenOrientation =  ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        }
+    }
+
+    private void applyFocusableFlag(State state) {
+        if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput) {
+            mLp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
+            mLp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        } else {
+            mLp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+            mLp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        }
+    }
+
+    private void applyHeight(State state) {
+        boolean expanded = state.isKeyguardShowingAndNotOccluded() || state.statusBarExpanded;
+        if (expanded) {
+            mLp.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        } else {
+            mLp.height = mBarHeight;
+        }
+    }
+
+    private void applyUserActivityTimeout(State state) {
+        if (state.isKeyguardShowingAndNotOccluded()) {
+            mLp.userActivityTimeout = state.keyguardUserActivityTimeout;
+        } else {
+            mLp.userActivityTimeout = -1;
+        }
+    }
+
+    private void applyInputFeatures(State state) {
+        if (state.isKeyguardShowingAndNotOccluded()) {
+            mLp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+        } else {
+            mLp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+        }
+    }
+
+    private void apply(State state) {
+        applyKeyguardFlags(state);
+        applyFocusableFlag(state);
+        adjustScreenOrientation(state);
+        applyHeight(state);
+        applyUserActivityTimeout(state);
+        applyInputFeatures(state);
+        mWindowManager.updateViewLayout(mStatusBarView, mLp);
+    }
+
+    public void setKeyguardShowing(boolean showing) {
+        mCurrentState.keyguardShowing = showing;
+        apply(mCurrentState);
+    }
+
+    public void setKeyguardOccluded(boolean occluded) {
+        mCurrentState.keyguardOccluded = occluded;
+        apply(mCurrentState);
+    }
+
+    public void setKeyguardNeedsInput(boolean needsInput) {
+        mCurrentState.keyguardNeedsInput = needsInput;
+        apply(mCurrentState);
+    }
+
+    public void setStatusBarExpanded(boolean expanded) {
+        mCurrentState.statusBarExpanded = expanded;
+        mCurrentState.statusBarFocusable = expanded;
+        apply(mCurrentState);
+    }
+
+    public void setStatusBarFocusable(boolean focusable) {
+        mCurrentState.statusBarFocusable = focusable;
+        apply(mCurrentState);
+    }
+
+    public void setKeyguardUserActivityTimeout(long timeout) {
+        mCurrentState.keyguardUserActivityTimeout = timeout;
+        apply(mCurrentState);
+    }
+
+    private static class State {
+        boolean keyguardShowing;
+        boolean keyguardOccluded;
+        boolean keyguardNeedsInput;
+        boolean statusBarExpanded;
+        boolean statusBarFocusable;
+        long keyguardUserActivityTimeout;
+
+        private boolean isKeyguardShowingAndNotOccluded() {
+            return keyguardShowing && !keyguardOccluded;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index a7121c4..dd89f47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -79,7 +79,7 @@
         switch (event.getKeyCode()) {
         case KeyEvent.KEYCODE_BACK:
             if (!down) {
-                mService.animateCollapsePanels();
+                mService.onBackPressed();
             }
             return true;
         }
@@ -90,7 +90,8 @@
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         boolean intercept = false;
         if (mNotificationPanel.isFullyExpanded()
-                && mStackScrollLayout.getVisibility() == View.VISIBLE) {
+                && mStackScrollLayout.getVisibility() == View.VISIBLE
+                && !mService.isOnKeyguard()) {
             intercept = mExpandHelper.onInterceptTouchEvent(ev);
         }
         if (!intercept) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 79932a7..2dba669 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -78,7 +78,7 @@
         }
 
         if (mHeadsUp != null) {
-            mHeadsUp.row.setExpanded(true);
+            mHeadsUp.row.setSystemExpanded(true);
             mHeadsUp.row.setShowingPublic(false);
             if (mContentHolder == null) {
                 // too soon!
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e2d6c5b..9800bc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -89,7 +89,7 @@
      * The current State this Layout is in
      */
     private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
-    
+
     private OnChildLocationsChangedListener mListener;
 
     public NotificationStackScrollLayout(Context context) {
@@ -336,7 +336,7 @@
                 continue;
             }
             float top = slidingChild.getTranslationY();
-            float bottom = top + slidingChild.getMeasuredHeight();
+            float bottom = top + slidingChild.getHeight();
             int left = slidingChild.getLeft();
             int right = slidingChild.getRight();
 
@@ -656,9 +656,11 @@
         int height = 0;
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
-            height += child.getHeight();
-            if (i < getChildCount()-1) {
-                height += mPaddingBetweenElements;
+            if (child.getVisibility() != View.GONE) {
+                height += child.getHeight();
+                if (i < getChildCount()-1) {
+                    height += mPaddingBetweenElements;
+                }
             }
         }
         mContentHeight = height;
@@ -713,6 +715,13 @@
     protected void onViewRemoved(View child) {
         super.onViewRemoved(child);
         mCurrentStackScrollState.removeViewStateForView(child);
+        mStackScrollAlgorithm.notifyChildrenChanged(this);
+    }
+
+    @Override
+    protected void onViewAdded(View child) {
+        super.onViewAdded(child);
+        mStackScrollAlgorithm.notifyChildrenChanged(this);
     }
 
     private boolean onInterceptTouchEventScroll(MotionEvent ev) {
@@ -858,6 +867,21 @@
         return Math.max(getHeight() - mContentHeight, 0);
     }
 
+    public void onExpansionStarted() {
+        mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
+    }
+
+    public void onExpansionStopped() {
+        mStackScrollAlgorithm.onExpansionStopped();
+    }
+
+    public void setIsExpanded(boolean isExpanded) {
+        mStackScrollAlgorithm.setIsExpanded(isExpanded);
+        if (!isExpanded) {
+            mOwnScrollY = 0;
+        }
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 4745f3b..431f6fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -21,6 +21,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
+import java.util.ArrayList;
 
 /**
  * The Algorithm of the {@link com.android.systemui.statusbar.stack
@@ -46,6 +49,11 @@
 
     private float mLayoutHeight;
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
+    private boolean mIsExpansionChanging;
+    private int mFirstChildMaxHeight;
+    private boolean mIsExpanded;
+    private View mFirstChildWhileExpanding;
+    private boolean mExpandedOnStart;
 
     public StackScrollAlgorithm(Context context) {
         initConstants(context);
@@ -92,6 +100,7 @@
         algorithmState.lastTopStackIndex = 0;
         algorithmState.scrollY = resultState.getScrollY();
         algorithmState.itemsInBottomStack = 0.0f;
+        updateVisibleChildren(resultState, algorithmState);
 
         // Phase 1:
         findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState);
@@ -107,6 +116,23 @@
     }
 
     /**
+     * Update the visible children on the state.
+     */
+    private void updateVisibleChildren(StackScrollState resultState,
+            StackScrollAlgorithmState state) {
+        ViewGroup hostView = resultState.getHostView();
+        int childCount = hostView.getChildCount();
+        state.visibleChildren.clear();
+        state.visibleChildren.ensureCapacity(childCount);
+        for (int i = 0; i < childCount; i++) {
+            View v = hostView.getChildAt(i);
+            if (v.getVisibility() != View.GONE) {
+                state.visibleChildren.add(v);
+            }
+        }
+    }
+
+    /**
      * Determine the positions for the views. This is the main part of the algorithm.
      *
      * @param resultState The result state to update if a change to the properties of a child occurs
@@ -117,8 +143,11 @@
             StackScrollAlgorithmState algorithmState) {
         float stackHeight = getLayoutHeight();
 
+        // The starting position of the bottom stack peek
+        float bottomPeekStart = stackHeight - mBottomStackPeekSize;
+
         // The position where the bottom stack starts.
-        float transitioningPositionStart = stackHeight - mCollapsedSize - mBottomStackPeekSize;
+        float transitioningPositionStart = bottomPeekStart - mCollapsedSize;
 
         // The y coordinate of the current child.
         float currentYPosition = 0.0f;
@@ -126,11 +155,10 @@
         // How far in is the element currently transitioning into the bottom stack.
         float yPositionInScrollView = 0.0f;
 
-        ViewGroup hostView = resultState.getHostView();
-        int childCount = hostView.getChildCount();
+        int childCount = algorithmState.visibleChildren.size();
         int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack;
         for (int i = 0; i < childCount; i++) {
-            View child = hostView.getChildAt(i);
+            View child = algorithmState.visibleChildren.get(i);
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             childViewState.yTranslation = currentYPosition;
             childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
@@ -151,8 +179,8 @@
                 // Case 2:
                 // First element of regular scrollview comes next, so the position is just the
                 // scrolling position
-                nextYPosition = Math.min(scrollOffset, transitioningPositionStart);
-                childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+                nextYPosition = updateStateForFirstScrollingChild(transitioningPositionStart,
+                        childViewState, scrollOffset);
             } else if (nextYPosition >= transitioningPositionStart) {
                 if (currentYPosition >= transitioningPositionStart) {
                     // Case 3:
@@ -186,6 +214,32 @@
         }
     }
 
+    /**
+     * Update the state for the first child which is in the regular scrolling area.
+     *
+     * @param transitioningPositionStart the transition starting position of the bottom stack
+     * @param childViewState the view state of the child
+     * @param scrollOffset the position in the regular scroll view after this child
+     * @return the next child position
+     */
+    private float updateStateForFirstScrollingChild(float transitioningPositionStart,
+            StackScrollState.ViewState childViewState, float scrollOffset) {
+        childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+        if (scrollOffset < transitioningPositionStart) {
+            return scrollOffset;
+        } else {
+            return transitioningPositionStart;
+        }
+    }
+
+    private int getMaxAllowedChildHeight(View child) {
+        if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            return row.getMaximumAllowedExpandHeight();
+        }
+        return child.getHeight();
+    }
+
     private float updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
             float stackHeight, float transitioningPositionStart, float currentYPosition,
             StackScrollState.ViewState childViewState, int childHeight, float nextYPosition) {
@@ -282,12 +336,11 @@
 
         // The y Position if the element would be in a regular scrollView
         float yPositionInScrollView = 0.0f;
-        ViewGroup hostView = resultState.getHostView();
-        int childCount = hostView.getChildCount();
+        int childCount = algorithmState.visibleChildren.size();
 
         // find the number of elements in the top stack.
         for (int i = 0; i < childCount; i++) {
-            View child = hostView.getChildAt(i);
+            View child = algorithmState.visibleChildren.get(i);
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             int childHeight = child.getHeight();
             float yPositionInScrollViewAfterElement = yPositionInScrollView
@@ -335,7 +388,17 @@
                 }
             } else {
                 algorithmState.lastTopStackIndex = i;
+                if (i == 0) {
 
+                    // The starting position of the bottom stack peek
+                    float bottomPeekStart = getLayoutHeight() - mBottomStackPeekSize;
+                    // Collapse and expand the first child while the shade is being expanded
+                    float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
+                            ? mFirstChildMaxHeight
+                            : childHeight;
+                    childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+                            mCollapsedSize);
+                }
                 // We are already past the stack so we can end the loop
                 break;
             }
@@ -352,10 +415,9 @@
      */
     private void updateZValuesForState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState) {
-        ViewGroup hostView = resultState.getHostView();
-        int childCount = hostView.getChildCount();
+        int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
-            View child = hostView.getChildAt(i);
+            View child = algorithmState.visibleChildren.get(i);
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             if (i < algorithmState.itemsInTopStack) {
                 float stackIndex = algorithmState.itemsInTopStack - i;
@@ -381,6 +443,57 @@
         this.mLayoutHeight = layoutHeight;
     }
 
+    public void onExpansionStarted(StackScrollState currentState) {
+        mIsExpansionChanging = true;
+        mExpandedOnStart = mIsExpanded;
+        ViewGroup hostView = currentState.getHostView();
+        updateFirstChildHeightWhileExpanding(hostView);
+    }
+
+    private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
+        mFirstChildWhileExpanding = findFirstVisibleChild(hostView);
+        if (mFirstChildWhileExpanding != null) {
+            if (mExpandedOnStart) {
+
+                // We are collapsing the shade, so the first child can get as most as high as the
+                // current height.
+                mFirstChildMaxHeight = mFirstChildWhileExpanding.getHeight();
+            } else {
+
+                // We are expanding the shade, expand it to its full height.
+                mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+            }
+        } else {
+            mFirstChildMaxHeight = 0;
+        }
+    }
+
+    private View findFirstVisibleChild(ViewGroup container) {
+        int childCount = container.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = container.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public void onExpansionStopped() {
+        mIsExpansionChanging = false;
+        mFirstChildWhileExpanding = null;
+    }
+
+    public void setIsExpanded(boolean isExpanded) {
+        this.mIsExpanded = isExpanded;
+    }
+
+    public void notifyChildrenChanged(ViewGroup hostView) {
+        if (mIsExpansionChanging) {
+            updateFirstChildHeightWhileExpanding(hostView);
+        }
+    }
+
     class StackScrollAlgorithmState {
 
         /**
@@ -415,6 +528,11 @@
          * how far in is the element currently transitioning into the bottom stack
          */
         public float partialInBottom;
+
+        /**
+         * The children from the host view which are not gone.
+         */
+        public final ArrayList<View> visibleChildren = new ArrayList<View>();
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 67a1735..06a08f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -63,7 +63,8 @@
             }
             // initialize with the default values of the view
             viewState.height = child.getHeight();
-            viewState.alpha = 1.0f;
+            viewState.alpha = 1;
+            viewState.gone = child.getVisibility() == View.GONE;
         }
     }
 
@@ -116,7 +117,7 @@
                 // apply visibility
                 int oldVisibility = child.getVisibility();
                 int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
-                if (newVisibility != oldVisibility) {
+                if (newVisibility != oldVisibility && !state.gone) {
                     child.setVisibility(newVisibility);
                 }
 
@@ -164,6 +165,7 @@
         float yTranslation;
         float zTranslation;
         int height;
+        boolean gone;
 
         /**
          * The location this view is currently rendered at.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index dd13e31..d615542 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -22,6 +22,7 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 
+import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.BaseStatusBar;
 
@@ -93,10 +94,6 @@
     }
 
     @Override
-    protected void createAndAddWindows() {
-    }
-
-    @Override
     protected WindowManager.LayoutParams getSearchLayoutParams(
             LayoutParams layoutParams) {
         return null;
@@ -141,10 +138,19 @@
     }
 
     @Override
+    protected int getMaxKeyguardNotifications() {
+        return 0;
+    }
+
+    @Override
     public void animateExpandSettingsPanel() {
     }
 
     @Override
+    protected void createAndAddWindows() {
+    }
+
+    @Override
     protected void refreshLayout(int layoutDirection) {
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ccdacea..77e2462 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -96,6 +96,8 @@
 import android.view.animation.AnimationUtils;
 
 import com.android.internal.R;
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardServiceConstants;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
 import com.android.internal.statusbar.IStatusBarService;
@@ -174,6 +176,8 @@
      * Keyguard stuff
      */
     private WindowState mKeyguardScrim;
+    private boolean mKeyguardHidden;
+    private boolean mKeyguardDrawn;
 
     /* Table of Application Launch keys.  Maps from key codes to intent categories.
      *
@@ -248,7 +252,6 @@
     int[] mNavigationBarHeightForRotation = new int[4];
     int[] mNavigationBarWidthForRotation = new int[4];
 
-    WindowState mKeyguard = null;
     KeyguardServiceDelegate mKeyguardDelegate;
     GlobalActions mGlobalActions;
     volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
@@ -986,7 +989,7 @@
         initializeHdmiState();
 
         // Match current screen state.
-        if (mPowerManager.isScreenOn()) {
+        if (mPowerManager.isInteractive()) {
             screenTurningOn(null);
         } else {
             screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
@@ -1311,7 +1314,6 @@
             case TYPE_BOOT_PROGRESS:
             case TYPE_DISPLAY_OVERLAY:
             case TYPE_HIDDEN_NAV_CONSUMER:
-            case TYPE_KEYGUARD:
             case TYPE_KEYGUARD_SCRIM:
             case TYPE_KEYGUARD_DIALOG:
             case TYPE_MAGNIFICATION_OVERLAY:
@@ -1348,6 +1350,22 @@
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
                 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
                 break;
+            case TYPE_STATUS_BAR:
+
+                // If the Keyguard is in a hidden state (occluded by another window), we force to
+                // remove the wallpaper and keyguard flag so that any change in-flight after setting
+                // the keyguard as occluded wouldn't set these flags again.
+                // See {@link #processKeyguardSetHiddenResultLw}.
+                if (mKeyguardHidden) {
+                    attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+                    attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+                }
+                break;
+        }
+
+        if (attrs.type != TYPE_STATUS_BAR) {
+            // The status bar is the only window allowed to exhibit keyguard behavior.
+            attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
     }
     
@@ -1434,54 +1452,50 @@
         case TYPE_KEYGUARD_SCRIM:
             // the safety window that shows behind keyguard while keyguard is starting
             return 12;
-        case TYPE_KEYGUARD:
-            // the keyguard; nothing on top of these can take focus, since they are
-            // responsible for power management when displayed.
-            return 13;
-        case TYPE_KEYGUARD_DIALOG:
-            return 14;
         case TYPE_STATUS_BAR_SUB_PANEL:
-            return 15;
+            return 13;
         case TYPE_STATUS_BAR:
-            return 16;
+            return 14;
         case TYPE_STATUS_BAR_PANEL:
-            return 17;
+            return 15;
+        case TYPE_KEYGUARD_DIALOG:
+            return 16;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 18;
+            return 17;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 19;
+            return 18;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 20;
+            return 19;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 21;
+            return 20;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 22;
+            return 21;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 23;
+            return 22;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 24;
+            return 23;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 25;
+            return 24;
         case TYPE_SECURE_SYSTEM_OVERLAY:
-            return 26;
+            return 25;
         case TYPE_BOOT_PROGRESS:
-            return 27;
+            return 26;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 28;
+            return 27;
         case TYPE_HIDDEN_NAV_CONSUMER:
-            return 29;
+            return 28;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
@@ -1551,7 +1565,7 @@
 
     @Override
     public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
-        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
+        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
     }
 
     @Override
@@ -1562,7 +1576,6 @@
             case TYPE_WALLPAPER:
             case TYPE_DREAM:
             case TYPE_UNIVERSE_BACKGROUND:
-            case TYPE_KEYGUARD:
             case TYPE_KEYGUARD_SCRIM:
                 return false;
             default:
@@ -1761,12 +1774,6 @@
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
                 break;
-            case TYPE_KEYGUARD:
-                if (mKeyguard != null) {
-                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                }
-                mKeyguard = win;
-                break;
             case TYPE_KEYGUARD_SCRIM:
                 if (mKeyguardScrim != null) {
                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
@@ -1783,9 +1790,6 @@
         if (mStatusBar == win) {
             mStatusBar = null;
             mStatusBarController.setWindow(null);
-        } else if (mKeyguard == win) {
-            Log.v(TAG, "Removing keyguard window (Did it crash?)");
-            mKeyguard = null;
             mKeyguardDelegate.showScrim();
         } else if (mKeyguardScrim == win) {
             Log.v(TAG, "Removing keyguard scrim");
@@ -1804,12 +1808,13 @@
         if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
               + ": transit=" + transit);
         if (win == mStatusBar) {
+            boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
             if (transit == TRANSIT_EXIT
                     || transit == TRANSIT_HIDE) {
-                return R.anim.dock_top_exit;
+                return isKeyguard ? -1 : R.anim.dock_top_exit;
             } else if (transit == TRANSIT_ENTER
                     || transit == TRANSIT_SHOW) {
-                return R.anim.dock_top_enter;
+                return isKeyguard ? -1 : R.anim.dock_top_enter;
             }
         } else if (win == mNavigationBar) {
             // This can be on either the bottom or the right.
@@ -2030,9 +2035,9 @@
             WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
             if (attrs != null) {
                 final int type = attrs.type;
-                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
-                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
-                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
+                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
+                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
+                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     // the "app" is keyguard, so give it the key
                     return 0;
                 }
@@ -2357,7 +2362,7 @@
     }
 
     private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
-        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
         if ((actions & ACTION_PASS_TO_USER) != 0) {
             long delayMillis = interceptKeyBeforeDispatching(
                     win, fallbackEvent, policyFlags);
@@ -2461,7 +2466,7 @@
      * given the situation with the keyguard.
      */
     void launchHomeFromHotKey() {
-        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotHidden()) {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotOccluded()) {
             // don't launch home if keyguard showing
         } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
             // when in keyguard restricted mode, must first verify unlock
@@ -3083,9 +3088,8 @@
                                 + mOverscanScreenHeight;
                     } else if (canHideNavigationBar()
                             && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
-                            && (attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD || (
-                                attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
+                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                         // Asking for layout as if the nav bar is hidden, lets the
                         // application extend into the unrestricted overscan screen area.  We
                         // only do this for application windows to ensure no window that
@@ -3392,16 +3396,19 @@
             mForcingShowNavBar = true;
             mForcingShowNavBarLayer = win.getSurfaceLayer();
         }
+        if (attrs.type == TYPE_STATUS_BAR && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+            mForceStatusBarFromKeyguard = true;
+        }
         if (mTopFullscreenOpaqueWindowState == null &&
                 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
-                if (attrs.type == TYPE_KEYGUARD) {
+                if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     mForceStatusBarFromKeyguard = true;
                 } else {
                     mForceStatusBar = true;
                 }
             }
-            if (attrs.type == TYPE_KEYGUARD) {
+            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                 mShowingLockscreen = true;
             }
             boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
@@ -3531,11 +3538,12 @@
 
         // Hide the key guard if a visible window explicitly specifies that it wants to be
         // displayed when the screen is locked.
-        if (mKeyguard != null) {
+        if (mKeyguardDelegate != null && mStatusBar != null) {
             if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
                     + mHideLockScreen);
             if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !isKeyguardSecure()) {
-                if (mKeyguard.hideLw(true)) {
+                mKeyguardHidden = true;
+                if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
@@ -3549,24 +3557,22 @@
                     });
                 }
             } else if (mHideLockScreen) {
-                if (mKeyguard.hideLw(true)) {
+                mKeyguardHidden = true;
+                if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
-                if (!mShowingDream) {
-                    mKeyguardDelegate.setHidden(true);
-                }
             } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
                 // This is the case of keyguard isSecure() and not mHideLockScreen.
                 if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
                     // Only launch the next keyguard unlock window once per window.
-                    if (mKeyguard.showLw(true)) {
+                    mKeyguardHidden = false;
+                    if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT
                                 | FINISH_LAYOUT_REDO_CONFIG
                                 | FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    mKeyguardDelegate.setHidden(false);
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
@@ -3576,12 +3582,12 @@
                 }
             } else {
                 mWinDismissingKeyguard = null;
-                if (mKeyguard.showLw(true)) {
+                mKeyguardHidden = false;
+                if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
-                mKeyguardDelegate.setHidden(false);
             }
         }
 
@@ -3596,9 +3602,39 @@
         return changes;
     }
 
+    /**
+     * Processes the result code of {@link IKeyguardService#setOccluded}. This is needed because we
+     * immediately need to put the wallpaper directly behind the Keyguard when a window with flag
+     * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} gets dismissed. If we
+     * would wait for Keyguard to change the flags, that would be running asynchronously and thus be
+     * too late so the user might see the window behind.
+     *
+     * @param setHiddenResult The result code from {@link IKeyguardService#setOccluded}.
+     * @return Whether the flags have changed and we have to redo the layout.
+     */
+    private boolean processKeyguardSetHiddenResultLw(int setHiddenResult) {
+        if (setHiddenResult
+                == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS) {
+            mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+            mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            return true;
+        } else if (setHiddenResult
+                == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS) {
+            mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+            mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isStatusBarKeyguard() {
+        return mStatusBar != null
+                && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+    }
+
     public boolean allowAppAnimationsLw() {
-        if (mKeyguard != null && mKeyguard.isVisibleLw() && !mKeyguard.isAnimatingLw()
-                || mShowingDream) {
+        if (isStatusBarKeyguard() || mShowingDream) {
             // If keyguard or dreams is currently visible, no reason to animate behind it.
             return false;
         }
@@ -3801,12 +3837,13 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
         if (!mSystemBooted) {
             // If we have not yet booted, don't let key events do anything.
             return 0;
         }
 
+        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int keyCode = event.getKeyCode();
@@ -3818,8 +3855,8 @@
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
         final boolean keyguardActive = (mKeyguardDelegate == null ? false :
-                                            (isScreenOn ?
-                                                mKeyguardDelegate.isShowingAndNotHidden() :
+                                            (interactive ?
+                                                mKeyguardDelegate.isShowingAndNotOccluded() :
                                                 mKeyguardDelegate.isShowing()));
 
         if (keyCode == KeyEvent.KEYCODE_POWER
@@ -3830,7 +3867,7 @@
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                    + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
                     + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
@@ -3839,18 +3876,11 @@
             performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
         }
 
-        // Basic policy based on screen state and keyguard.
-        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
-        //        is on or off, really.  We should care about whether the device is in an
-        //        interactive state or is in suspend pretending to be "off".
-        //        The primary screen might be turned off due to proximity sensor or
-        //        because we are presenting media on an auxiliary screen or remotely controlling
-        //        the device some other way (which is why we have an exemption here for injected
-        //        events).
+        // Basic policy based on interactive state.
         int result;
         boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
                 | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-        if (isScreenOn || (isInjected && !isWakeKey)) {
+        if (interactive || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
@@ -3875,7 +3905,7 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
-                        if (isScreenOn && !mVolumeDownKeyTriggered
+                        if (interactive && !mVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeDownKeyTriggered = true;
                             mVolumeDownKeyTime = event.getDownTime();
@@ -3889,7 +3919,7 @@
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (isScreenOn && !mVolumeUpKeyTriggered
+                        if (interactive && !mVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeUpKeyTriggered = true;
                             cancelPendingPowerKeyAction();
@@ -3957,7 +3987,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                    interceptPowerKeyDown(!interactive || hungUp);
                 } else {
                     if (interceptPowerKeyUp(canceled)) {
                         if ((mEndcallBehavior
@@ -3979,12 +4009,12 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
+                    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
                             event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
                     if (panic) {
                         mHandler.post(mRequestTransientNav);
                     }
-                    if (isScreenOn && !mPowerKeyTriggered
+                    if (interactive && !mPowerKeyTriggered
                             && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                         mPowerKeyTriggered = true;
                         mPowerKeyTime = event.getDownTime();
@@ -4001,7 +4031,7 @@
                                 telephonyService.silenceRinger();
                             } else if ((mIncallPowerBehavior
                                     & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                                    && telephonyService.isOffhook() && isScreenOn) {
+                                    && telephonyService.isOffhook() && interactive) {
                                 // Otherwise, if "Power button ends call" is enabled,
                                 // the Power button will hang up any current active call.
                                 hungUp = telephonyService.endCall();
@@ -4010,7 +4040,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp
+                    interceptPowerKeyDown(!interactive || hungUp
                             || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
                 } else {
                     mPowerKeyTriggered = false;
@@ -4143,15 +4173,12 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        int result = 0;
-
-        final boolean isWakeMotion = (policyFlags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-        if (isWakeMotion) {
-            mPowerManager.wakeUp(whenNanos / 1000000);
-        }
-        return result;
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        // We already know this is a wake motion so just wake up.
+        // Note that we would observe policyFlags containing
+        // FLAG_WAKE and FLAG_INTERACTIVE here.
+        mPowerManager.wakeUp(whenNanos / 1000000);
+        return 0;
     }
 
     void dispatchMediaKeyWithWakeLock(KeyEvent event) {
@@ -4328,21 +4355,16 @@
 
     private void waitForKeyguard(final ScreenOnListener screenOnListener) {
         if (mKeyguardDelegate != null) {
-            if (screenOnListener != null) {
-                mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() {
-                    @Override
-                    public void onShown(IBinder windowToken) {
-                        waitForKeyguardWindowDrawn(windowToken, screenOnListener);
-                    }
-                });
-                return;
-            } else {
-                mKeyguardDelegate.onScreenTurnedOn(null);
-            }
+            mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() {
+                @Override
+                public void onShown(IBinder windowToken) {
+                    waitForKeyguardWindowDrawn(windowToken, screenOnListener);
+                }
+            });
         } else {
             Slog.i(TAG, "No keyguard interface!");
+            finishScreenTurningOn(screenOnListener);
         }
-        finishScreenTurningOn(screenOnListener);
     }
 
     private void waitForKeyguardWindowDrawn(IBinder windowToken,
@@ -4355,6 +4377,7 @@
                     public void sendResult(Bundle data) {
                         Slog.i(TAG, "Lock screen displayed!");
                         finishScreenTurningOn(screenOnListener);
+                        setKeyguardDrawn();
                     }
                 })) {
                     return;
@@ -4368,6 +4391,7 @@
 
         Slog.i(TAG, "No lock screen! windowToken=" + windowToken);
         finishScreenTurningOn(screenOnListener);
+        setKeyguardDrawn();
     }
 
     private void finishScreenTurningOn(ScreenOnListener screenOnListener) {
@@ -4411,7 +4435,7 @@
 
     private boolean keyguardIsShowingTq() {
         if (mKeyguardDelegate == null) return false;
-        return mKeyguardDelegate.isShowingAndNotHidden();
+        return mKeyguardDelegate.isShowingAndNotOccluded();
     }
 
 
@@ -4448,6 +4472,23 @@
         }
     }
 
+    private void setKeyguardDrawn() {
+        synchronized (mLock) {
+            mKeyguardDrawn = true;
+        }
+        try {
+            mWindowManager.enableScreenIfNeeded();
+        } catch (RemoteException unhandled) {
+        }
+    }
+
+    @Override
+    public boolean isKeyguardDrawnLw() {
+        synchronized (mLock) {
+            return mKeyguardDrawn;
+        }
+    }
+
     void sendCloseSystemWindows() {
         sendCloseSystemWindows(mContext, null);
     }
@@ -4731,6 +4772,7 @@
         synchronized (mLock) {
             mSystemBooted = true;
         }
+        waitForKeyguard(null);
     }
 
     ProgressDialog mBootMsgDialog = null;
@@ -5055,7 +5097,7 @@
         }
         final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
-        if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotHidden())) {
+        if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotOccluded())) {
             return false;
         }
         long[] pattern = null;
@@ -5106,7 +5148,7 @@
 
     @Override
     public void keepScreenOnStoppedLw() {
-        if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) {
+        if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotOccluded()) {
             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
     }
@@ -5118,7 +5160,7 @@
         if (win == null) {
             return 0;
         }
-        if (win.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) {
+        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
             // We are updating at a point where the keyguard has gotten
             // focus, but we were last in a state where the top window is
             // hiding it.  This is probably because the keyguard as been
@@ -5164,8 +5206,8 @@
 
     private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
         // apply translucent bar vis flags
-        WindowState transWin = mKeyguard != null && mKeyguard.isVisibleLw() && !mHideLockScreen
-                ? mKeyguard
+        WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
+                ? mStatusBar
                 : mTopFullscreenOpaqueWindowState;
         vis = mStatusBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
         vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
@@ -5176,9 +5218,10 @@
             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                     | View.SYSTEM_UI_FLAG_IMMERSIVE
-                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.STATUS_BAR_TRANSLUCENT
-                    | View.NAVIGATION_BAR_TRANSLUCENT;
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+            if (!isStatusBarKeyguard() || mHideLockScreen) {
+                flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
+            }
             vis = (vis & ~flags) | (oldVis & flags);
         }
 
@@ -5423,15 +5466,13 @@
         if (mStatusBar != null) {
             pw.print(prefix); pw.print("mStatusBar=");
                     pw.println(mStatusBar);
+            pw.print(prefix); pw.print("isStatusBarKeyguard=");
+                    pw.print(isStatusBarKeyguard());
         }
         if (mNavigationBar != null) {
             pw.print(prefix); pw.print("mNavigationBar=");
                     pw.println(mNavigationBar);
         }
-        if (mKeyguard != null) {
-            pw.print(prefix); pw.print("mKeyguard=");
-                    pw.println(mKeyguard);
-        }
         if (mFocusedWindow != null) {
             pw.print(prefix); pw.print("mFocusedWindow=");
                     pw.println(mFocusedWindow);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index 812e817..966924b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -29,8 +29,8 @@
  */
 public class KeyguardServiceDelegate {
     // TODO: propagate changes to these to {@link KeyguardTouchDelegate}
-    public static final String KEYGUARD_PACKAGE = "com.android.keyguard";
-    public static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
+    public static final String KEYGUARD_PACKAGE = "com.android.systemui";
+    public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";
 
     private static final String TAG = "KeyguardServiceDelegate";
     private static final boolean DEBUG = true;
@@ -44,13 +44,13 @@
             // the event something checks before the service is actually started.
             // KeyguardService itself should default to this state until the real state is known.
             showing = true;
-            showingAndNotHidden = true;
+            showingAndNotOccluded = true;
             secure = true;
         }
         boolean showing;
-        boolean showingAndNotHidden;
+        boolean showingAndNotOccluded;
         boolean inputRestricted;
-        boolean hidden;
+        boolean occluded;
         boolean secure;
         boolean dreaming;
         boolean systemIsReady;
@@ -109,7 +109,7 @@
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
             if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
             mKeyguardState.showing = false;
-            mKeyguardState.showingAndNotHidden = false;
+            mKeyguardState.showingAndNotOccluded = false;
             mKeyguardState.secure = false;
         } else {
             if (DEBUG) Log.v(TAG, "*** Keyguard started");
@@ -148,11 +148,11 @@
         return mKeyguardState.showing;
     }
 
-    public boolean isShowingAndNotHidden() {
+    public boolean isShowingAndNotOccluded() {
         if (mKeyguardService != null) {
-            mKeyguardState.showingAndNotHidden = mKeyguardService.isShowingAndNotHidden();
+            mKeyguardState.showingAndNotOccluded = mKeyguardService.isShowingAndNotOccluded();
         }
-        return mKeyguardState.showingAndNotHidden;
+        return mKeyguardState.showingAndNotOccluded;
     }
 
     public boolean isInputRestricted() {
@@ -174,11 +174,13 @@
         }
     }
 
-    public void setHidden(boolean isHidden) {
+    public int setOccluded(boolean isOccluded) {
+        int result = 0;
         if (mKeyguardService != null) {
-            mKeyguardService.setHidden(isHidden);
+            result = mKeyguardService.setOccluded(isOccluded);
         }
-        mKeyguardState.hidden = isHidden;
+        mKeyguardState.occluded = isOccluded;
+        return result;
     }
 
     public void dismiss() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index 9fb2a50..7cb48fa 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -22,6 +22,7 @@
 import android.util.Slog;
 import android.view.MotionEvent;
 
+import com.android.internal.policy.IKeyguardServiceConstants;
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -57,9 +58,9 @@
         return false; // TODO cache state
     }
 
-    public boolean isShowingAndNotHidden() {
+    public boolean isShowingAndNotOccluded() {
         try {
-            return mService.isShowingAndNotHidden();
+            return mService.isShowingAndNotOccluded();
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
@@ -100,11 +101,12 @@
         }
     }
 
-    public void setHidden(boolean isHidden) {
+    public int setOccluded(boolean isOccluded) {
         try {
-            mService.setHidden(isHidden);
+            return mService.setOccluded(isOccluded);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
+            return IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE;
         }
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c3db55e..3619112 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -132,6 +132,8 @@
     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
 
+    private static final String GET_WINDOW_TOKEN = "getWindowToken";
+
     private static final ComponentName sFakeAccessibilityServiceComponentName =
             new ComponentName("foo.bar", "FakeService");
 
@@ -164,8 +166,6 @@
 
     private final Point mTempPoint = new Point();
 
-    private final Display mDefaultDisplay;
-
     private final PackageManager mPackageManager;
 
     private final WindowManagerInternal mWindowManagerService;
@@ -174,7 +174,7 @@
 
     private final MainHandler mMainHandler;
 
-    private Service mQueryBridge;
+    private InteractionBridge mInteractionBridge;
 
     private AlertDialog mEnableTouchExplorationDialog;
 
@@ -230,10 +230,6 @@
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
-        //TODO: (multi-display) We need to support multiple displays.
-        DisplayManager displayManager = (DisplayManager)
-                mContext.getSystemService(Context.DISPLAY_SERVICE);
-        mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
         registerBroadcastReceivers();
         new AccessibilityContentObserver(mMainHandler).register(
                 context.getContentResolver());
@@ -360,6 +356,7 @@
         }, UserHandle.ALL, intentFilter, null, null);
     }
 
+    @Override
     public int addClient(IAccessibilityManagerClient client, int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -388,6 +385,7 @@
         }
     }
 
+    @Override
     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -397,7 +395,8 @@
                 return true; // yes, recycle the event
             }
             if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
-                mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
+                mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
+                        event.getSourceNodeId(), event.getEventType());
                 mSecurityPolicy.updateEventSourceLocked(event);
                 notifyAccessibilityServicesDelayedLocked(event, false);
                 notifyAccessibilityServicesDelayedLocked(event, true);
@@ -412,6 +411,7 @@
         return (OWN_PROCESS_ID != Binder.getCallingPid());
     }
 
+    @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
             final int resolvedUserId = mSecurityPolicy
@@ -430,6 +430,7 @@
         }
     }
 
+    @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
         List<AccessibilityServiceInfo> result = null;
@@ -463,6 +464,7 @@
         return result;
     }
 
+    @Override
     public void interrupt(int userId) {
         CopyOnWriteArrayList<Service> services;
         synchronized (mLock) {
@@ -485,6 +487,7 @@
         }
     }
 
+    @Override
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
         synchronized (mLock) {
@@ -521,6 +524,7 @@
         }
     }
 
+    @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
         synchronized (mLock) {
             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
@@ -570,6 +574,7 @@
         return -1;
     }
 
+    @Override
     public void registerUiTestAutomationService(IBinder owner,
             IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo) {
@@ -612,6 +617,7 @@
         }
     }
 
+    @Override
     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
         synchronized (mLock) {
             UserState userState = getCurrentUserStateLocked();
@@ -630,6 +636,7 @@
         }
     }
 
+    @Override
     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
             ComponentName service, boolean touchExplorationEnabled) {
         mSecurityPolicy.enforceCallingPermission(
@@ -662,6 +669,29 @@
         }
     }
 
+    @Override
+    public IBinder getWindowToken(int windowId) {
+        mSecurityPolicy.enforceCallingPermission(
+                Manifest.permission.RETRIEVE_WINDOW_TOKEN,
+                GET_WINDOW_TOKEN);
+        synchronized (mLock) {
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(
+                            UserHandle.getCallingUserId());
+            if (resolvedUserId != mCurrentUserId) {
+                return null;
+            }
+            if (mSecurityPolicy.findWindowById(windowId) == null) {
+                return null;
+            }
+            IBinder token = mGlobalWindowTokens.get(windowId);
+            if (token != null) {
+                return token;
+            }
+            return getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        }
+    }
+
     boolean onGesture(int gestureId) {
         synchronized (mLock) {
             boolean handled = notifyGestureLocked(gestureId, false);
@@ -689,47 +719,9 @@
      * @param outBounds The output to which to write the focus bounds.
      * @return Whether accessibility focus was found and the bounds are populated.
      */
-    // TODO: (multi-display) Make sure this works for multiple displays. 
-    boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
-        // Instead of keeping track of accessibility focus events per
-        // window to be able to find the focus in the active window,
-        // we take a stateless approach and look it up. This is fine
-        // since we do this only when the user clicks/long presses.
-        Service service = getQueryBridge();
-        final int connectionId = service.mId;
-        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        client.addConnection(connectionId, service);
-        try {
-            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
-                    .getRootInActiveWindow(connectionId);
-            if (root == null) {
-                return false;
-            }
-            AccessibilityNodeInfo focus = root.findFocus(
-                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-            if (focus == null) {
-                return false;
-            }
-            focus.getBoundsInScreen(outBounds);
-
-            MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId());
-            if (spec != null && !spec.isNop()) {
-                outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
-                outBounds.scale(1 / spec.scale);
-            }
-
-            // Clip to the window rectangle.
-            Rect windowBounds = mTempRect;
-            getActiveWindowBounds(windowBounds);
-            outBounds.intersect(windowBounds);
-            // Clip to the screen rectangle.
-            mDefaultDisplay.getRealSize(mTempPoint);
-            outBounds.intersect(0,  0,  mTempPoint.x, mTempPoint.y);
-
-            return true;
-        } finally {
-            client.removeConnection(connectionId);
-        }
+    // TODO: (multi-display) Make sure this works for multiple displays.
+    boolean getAccessibilityFocusBounds(Rect outBounds) {
+        return getInteractionBridgeLocked().getAccessibilityFocusBoundsNotLocked(outBounds);
     }
 
     /**
@@ -820,14 +812,11 @@
         }
     }
 
-    private Service getQueryBridge() {
-        if (mQueryBridge == null) {
-            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
-            info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
-            mQueryBridge = new Service(UserHandle.USER_NULL,
-                    sFakeAccessibilityServiceComponentName, info);
+    private InteractionBridge getInteractionBridgeLocked() {
+        if (mInteractionBridge == null) {
+            mInteractionBridge = new InteractionBridge();
         }
-        return mQueryBridge;
+        return mInteractionBridge;
     }
 
     private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
@@ -1298,9 +1287,10 @@
     private void onUserStateChangedLocked(UserState userState) {
         // TODO: Remove this hack
         mInitialized = true;
-        updateLegacyCapabilities(userState);
+        updateLegacyCapabilitiesLocked(userState);
         updateServicesLocked(userState);
-        updateWindowsForAccessibilityCallback(userState);
+        updateWindowsForAccessibilityCallbackLocked(userState);
+        updateAccessibilityFocusBehaviorLocked(userState);
         updateFilterKeyEventsLocked(userState);
         updateTouchExplorationLocked(userState);
         updateEnhancedWebAccessibilityLocked(userState);
@@ -1309,7 +1299,29 @@
         scheduleUpdateClientsIfNeededLocked(userState);
     }
 
-    private void updateWindowsForAccessibilityCallback(UserState userState) {
+    private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
+        // If there is no service that can operate with interactive windows
+        // then we keep the old behavior where a window loses accessibility
+        // focus if it is no longer active. This still changes the behavior
+        // for services that do not operate with interactive windows and run
+        // at the same time as the one(s) which does. In practice however,
+        // there is only one service that uses accessibility focus and it
+        // is typically the one that operates with interactive windows, So,
+        // this is fine. Note that to allow a service to work across windows
+        // we have to allow accessibility focus stay in any of them. Sigh...
+        List<Service> boundServices = userState.mBoundServices;
+        final int boundServiceCount = boundServices.size();
+        for (int i = 0; i < boundServiceCount; i++) {
+            Service boundService = boundServices.get(i);
+            if (boundService.canRetrieveInteractiveWindowsLocked()) {
+                userState.mAccessibilityFocusOnlyInActiveWindow = false;
+                return;
+            }
+        }
+        userState.mAccessibilityFocusOnlyInActiveWindow = true;
+    }
+
+    private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
         if (userState.mIsAccessibilityEnabled) {
             // We observe windows for accessibility only if there is at least
             // one bound service that can retrieve window content that specified
@@ -1322,8 +1334,7 @@
             final int boundServiceCount = boundServices.size();
             for (int i = 0; i < boundServiceCount; i++) {
                 Service boundService = boundServices.get(i);
-                if (mSecurityPolicy.canRetrieveWindowContentLocked(boundService)
-                        && boundService.mRetrieveInteractiveWindows) {
+                if (boundService.canRetrieveInteractiveWindowsLocked()) {
                     boundServiceCanRetrieveInteractiveWindows = true;
                     break;
                 }
@@ -1346,7 +1357,7 @@
         }
     }
 
-    private void updateLegacyCapabilities(UserState userState) {
+    private void updateLegacyCapabilitiesLocked(UserState userState) {
         // Up to JB-MR1 we had a white list with services that can enable touch
         // exploration. When a service is first started we show a dialog to the
         // use to get a permission to white list the service.
@@ -1547,6 +1558,18 @@
         DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
     }
 
+    private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
+        IBinder windowToken = mGlobalWindowTokens.get(windowId);
+        if (windowToken == null) {
+            windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        }
+        if (windowToken != null) {
+            return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
+                    windowToken);
+        }
+        return null;
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1623,6 +1646,7 @@
         public static final int MSG_UPDATE_INPUT_FILTER = 6;
         public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
+        public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
 
         public MainHandler(Looper looper) {
             super(looper);
@@ -1678,6 +1702,15 @@
                     Service service = (Service) msg.obj;
                     showEnableTouchExplorationDialog(service);
                 } break;
+
+                case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
+                    final int windowId = msg.arg1;
+                    InteractionBridge bridge;
+                    synchronized (mLock) {
+                        bridge = getInteractionBridgeLocked();
+                    }
+                    bridge.clearAccessibilityFocusNotLocked(windowId);
+                } break;
             }
         }
 
@@ -1946,6 +1979,11 @@
             }
         }
 
+        public boolean canRetrieveInteractiveWindowsLocked() {
+            return mSecurityPolicy.canRetrieveWindowContentLocked(this)
+                    && mRetrieveInteractiveWindows;
+        }
+
         @Override
         public void setServiceInfo(AccessibilityServiceInfo info) {
             final long identity = Binder.clearCallingIdentity();
@@ -2074,7 +2112,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
                         viewIdResName, interactionId, callback, mFetchFlags, interrogatingPid,
@@ -2118,7 +2156,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
@@ -2162,7 +2200,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
                         interactionId, callback, mFetchFlags | flags, interrogatingPid,
@@ -2192,7 +2230,8 @@
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
-                resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
+                resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
+                        accessibilityWindowId, focusType);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
@@ -2206,14 +2245,14 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
                         mFetchFlags, interrogatingPid, interrogatingTid, spec);
                 return true;
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
+                    Slog.e(LOG_TAG, "Error calling findFocus()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
@@ -2249,7 +2288,7 @@
             }
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
-            MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
+            MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
             try {
                 connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
                         mFetchFlags, interrogatingPid, interrogatingTid, spec);
@@ -2694,16 +2733,18 @@
             return accessibilityWindowId;
         }
 
-        private MagnificationSpec getCompatibleMagnificationSpec(int windowId) {
-            IBinder windowToken = mGlobalWindowTokens.get(windowId);
-            if (windowToken == null) {
-                windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
+        private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
+            if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
+                return mSecurityPolicy.mActiveWindowId;
             }
-            if (windowToken != null) {
-                return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
-                        windowToken);
+            if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) {
+                if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
+                    return mSecurityPolicy.mFocusedWindowId;
+                } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
+                    return mSecurityPolicy.mAccessibilityFocusedWindowId;
+                }
             }
-            return null;
+            return windowId;
         }
 
         private final class InvocationHandler extends Handler {
@@ -2972,7 +3013,6 @@
                     return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
                 }
 
-                case WindowManager.LayoutParams.TYPE_KEYGUARD:
                 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
@@ -2996,7 +3036,86 @@
         }
     }
 
+    private final class InteractionBridge {
+        private final Display mDefaultDisplay;
+        private final int mConnectionId;
+        private final AccessibilityInteractionClient mClient;
+
+        public InteractionBridge() {
+            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+            info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
+            info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+            info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+            Service service = new Service(UserHandle.USER_NULL,
+                    sFakeAccessibilityServiceComponentName, info);
+
+            mConnectionId = service.mId;
+
+            mClient = AccessibilityInteractionClient.getInstance();
+            mClient.addConnection(mConnectionId, service);
+
+            //TODO: (multi-display) We need to support multiple displays.
+            DisplayManager displayManager = (DisplayManager)
+                    mContext.getSystemService(Context.DISPLAY_SERVICE);
+            mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        }
+
+        public void clearAccessibilityFocusNotLocked(int windowId) {
+            AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
+            if (focus != null) {
+                focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+            }
+        }
+
+        public boolean getAccessibilityFocusBoundsNotLocked(Rect outBounds) {
+            AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
+            if (focus == null) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                focus.getBoundsInScreen(outBounds);
+
+                MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
+                if (spec != null && !spec.isNop()) {
+                    outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
+                    outBounds.scale(1 / spec.scale);
+                }
+
+                // Clip to the window rectangle.
+                Rect windowBounds = mTempRect;
+                getActiveWindowBounds(windowBounds);
+                outBounds.intersect(windowBounds);
+
+                // Clip to the screen rectangle.
+                mDefaultDisplay.getRealSize(mTempPoint);
+                outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
+
+                return true;
+            }
+        }
+
+        private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
+            final int focusedWindowId;
+            synchronized (mLock) {
+                focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId;
+                if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) {
+                    return null;
+                }
+            }
+            return getAccessibilityFocusNotLocked(focusedWindowId);
+        }
+
+        private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
+            return mClient.findFocus(mConnectionId,
+                    windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
+                    AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        }
+    }
+
     final class SecurityPolicy {
+        public static final int INVALID_WINDOW_ID = -1;
+
         private static final int VALID_ACTIONS =
             AccessibilityNodeInfo.ACTION_CLICK
             | AccessibilityNodeInfo.ACTION_LONG_CLICK
@@ -3040,8 +3159,11 @@
         public final List<AccessibilityWindowInfo> mWindows =
                 new ArrayList<AccessibilityWindowInfo>();
 
-        public int mActiveWindowId;
-        public int mFocusedWindowId;
+        public int mActiveWindowId = INVALID_WINDOW_ID;
+        public int mFocusedWindowId = INVALID_WINDOW_ID;
+        public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+        public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
         public AccessibilityEvent mShowingFocusedWindowEvent;
 
         private boolean mTouchInteractionInProgress;
@@ -3094,9 +3216,9 @@
                 mWindows.remove(i).recycle();
             }
 
-            mFocusedWindowId = -1;
+            mFocusedWindowId = INVALID_WINDOW_ID;
             if (!mTouchInteractionInProgress) {
-                mActiveWindowId = -1;
+                mActiveWindowId = INVALID_WINDOW_ID;
             }
 
             // If the active window goes away while the user is touch exploring we
@@ -3124,7 +3246,7 @@
                 }
 
                 if (mTouchInteractionInProgress && activeWindowGone) {
-                    mActiveWindowId = -1;
+                    mActiveWindowId = INVALID_WINDOW_ID;
                 }
 
                 // Focused window may change the active one, so set the
@@ -3158,7 +3280,8 @@
             }
         }
 
-        public void updateActiveWindowLocked(int windowId, int eventType) {
+        public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId,
+                int eventType) {
             // The active window is either the window that has input focus or
             // the window that the user is currently touching. If the user is
             // touching a window that does not have input focus as soon as the
@@ -3193,6 +3316,29 @@
                         }
                     }
                 } break;
+
+                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+                    synchronized (mLock) {
+                        if (mAccessibilityFocusedWindowId != windowId) {
+                            mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+                                    mAccessibilityFocusedWindowId, 0).sendToTarget();
+                            mAccessibilityFocusedWindowId = windowId;
+                            mAccessibilityFocusNodeId = nodeId;
+                        }
+                    }
+                } break;
+
+                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+                    synchronized (mLock) {
+                        if (mAccessibilityFocusNodeId == nodeId) {
+                            mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+                        }
+                        if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID
+                                && mAccessibilityFocusedWindowId == windowId) {
+                            mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
+                        }
+                    }
+                } break;
             }
         }
 
@@ -3213,7 +3359,19 @@
                 // (they are a result of user touching the screen) so change of
                 // the active window before all hover accessibility events from
                 // the touched window are delivered is fine.
+                final int oldActiveWindow = mSecurityPolicy.mActiveWindowId;
                 setActiveWindowLocked(mFocusedWindowId);
+
+                // If there is no service that can operate with active windows
+                // we keep accessibility focus behavior to constrain it only in
+                // the active window. Look at updateAccessibilityFocusBehaviorLocked
+                // for details.
+                if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
+                        && mAccessibilityFocusedWindowId == oldActiveWindow
+                        && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
+                    mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
+                            oldActiveWindow, 0).sendToTarget();
+                }
             }
         }
 
@@ -3368,6 +3526,7 @@
         public boolean mIsDisplayMagnificationEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mHasDisplayColorAdjustment;
+        public boolean mAccessibilityFocusOnlyInActiveWindow;
 
         private Service mUiAutomationService;
         private IAccessibilityServiceClient mUiAutomationServiceClient;
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 43f12eb..ac0ca0a 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -1159,7 +1159,7 @@
                 // No last touch explored event but there is accessibility focus in
                 // the active window. We click in the middle of the focus bounds.
                 Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                     clickLocationX = focusBounds.centerX();
                     clickLocationY = focusBounds.centerY();
                 } else {
@@ -1177,7 +1177,7 @@
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
                         Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                             if (!focusBounds.contains(clickLocationX, clickLocationY)) {
                                 clickLocationX = focusBounds.centerX();
                                 clickLocationY = focusBounds.centerY();
@@ -1332,7 +1332,7 @@
                 // No last touch explored event but there is accessibility focus in
                 // the active window. We click in the middle of the focus bounds.
                 Rect focusBounds = mTempRect;
-                if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                     clickLocationX = focusBounds.centerX();
                     clickLocationY = focusBounds.centerY();
                 } else {
@@ -1350,7 +1350,7 @@
                     mAms.getActiveWindowBounds(activeWindowBounds);
                     if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
                         Rect focusBounds = mTempRect;
-                        if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+                        if (mAms.getAccessibilityFocusBounds(focusBounds)) {
                             if (!focusBounds.contains(clickLocationX, clickLocationY)) {
                                 clickLocationX = focusBounds.centerX();
                                 clickLocationY = focusBounds.centerY();
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 1ed943c..7b3b65b 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -35,8 +35,12 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import com.android.internal.util.AsyncChannel;
@@ -433,14 +437,14 @@
                     case NativeResponseCode.SERVICE_FOUND:
                         /* NNN uniqueId serviceName regType domain */
                         if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                         clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
                                 clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_LOST:
                         /* NNN uniqueId serviceName regType domain */
                         if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                         clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
                                 clientId, servInfo);
                         break;
@@ -453,7 +457,7 @@
                     case NativeResponseCode.SERVICE_REGISTERED:
                         /* NNN regId serviceName regType */
                         if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], null, null);
+                        servInfo = new NsdServiceInfo(cooked[2], null);
                         clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
                                 id, clientId, servInfo);
                         break;
@@ -673,9 +677,22 @@
     private boolean registerService(int regId, NsdServiceInfo service) {
         if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
         try {
-            //Add txtlen and txtdata
-            mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
+            Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
                     service.getServiceType(), service.getPort());
+
+            // Add TXT records as additional arguments.
+            Map<String, byte[]> txtRecords = service.getAttributes();
+            for (String key : txtRecords.keySet()) {
+                try {
+                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
+                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
+                            new String(txtRecords.get(key), "UTF_8")));
+                } catch (UnsupportedEncodingException e) {
+                    Slog.e(TAG, "Failed to encode txtRecord " + e);
+                }
+            }
+
+            mNativeConnector.execute(cmd);
         } catch(NativeDaemonConnectorException e) {
             Slog.e(TAG, "Failed to execute registerService " + e);
             return false;
diff --git a/services/core/java/com/android/server/display/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
new file mode 100644
index 0000000..eb0ae6a
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -0,0 +1,24 @@
+/*
+ * 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.server.display;
+
+/**
+ * Interface used to update the actual display state.
+ */
+public interface DisplayBlanker {
+    void requestDisplayState(int state);
+}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9ec1122..a5f9822 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -107,15 +107,9 @@
     }
 
     /**
-     * Blanks the display, if supported.
+     * Sets the display state, if supported.
      */
-    public void blankLocked() {
-    }
-
-    /**
-     * Unblanks the display, if supported.
-     */
-    public void unblankLocked() {
+    public void requestDisplayStateLocked(int state) {
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 75f1f53..a77443d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -176,6 +176,11 @@
     public String address;
 
     /**
+     * Display state.
+     */
+    public int state = Display.STATE_ON;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -219,6 +224,7 @@
                 && rotation == other.rotation
                 && type == other.type
                 && Objects.equal(address, other.address)
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -241,6 +247,7 @@
         rotation = other.rotation;
         type = other.type;
         address = other.address;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -260,6 +267,7 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ").append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 693f7d8..071417b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -121,10 +121,6 @@
     private static final int MSG_REQUEST_TRAVERSAL = 4;
     private static final int MSG_UPDATE_VIEWPORT = 5;
 
-    private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
-    private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
-    private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
-
     private final Context mContext;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
@@ -176,8 +172,9 @@
     // Display power controller.
     private DisplayPowerController mDisplayPowerController;
 
-    // Set to true if all displays have been blanked by the power manager.
-    private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
+    // The overall display state, independent of changes that might influence one
+    // display or another in particular.
+    private int mGlobalDisplayState = Display.STATE_UNKNOWN;
 
     // Set to true when there are pending display changes that have yet to be applied
     // to the surface flinger state.
@@ -315,21 +312,11 @@
         }
     }
 
-    private void blankAllDisplaysFromPowerManagerInternal() {
+    private void requestGlobalDisplayStateInternal(int state) {
         synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
-                updateAllDisplayBlankingLocked();
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    private void unblankAllDisplaysFromPowerManagerInternal() {
-        synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
-                updateAllDisplayBlankingLocked();
+            if (mGlobalDisplayState != state) {
+                mGlobalDisplayState = state;
+                updateGlobalDisplayStateLocked();
                 scheduleTraversalLocked(false);
             }
         }
@@ -616,7 +603,7 @@
 
         mDisplayDevices.add(device);
         addLogicalDisplayLocked(device);
-        updateDisplayBlankingLocked(device);
+        updateDisplayStateLocked(device);
         scheduleTraversalLocked(false);
     }
 
@@ -655,27 +642,20 @@
         scheduleTraversalLocked(false);
     }
 
-    private void updateAllDisplayBlankingLocked() {
+    private void updateGlobalDisplayStateLocked() {
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
             DisplayDevice device = mDisplayDevices.get(i);
-            updateDisplayBlankingLocked(device);
+            updateDisplayStateLocked(device);
         }
     }
 
-    private void updateDisplayBlankingLocked(DisplayDevice device) {
+    private void updateDisplayStateLocked(DisplayDevice device) {
         // Blank or unblank the display immediately to match the state requested
-        // by the power manager (if known).
+        // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            switch (mAllDisplayBlankStateFromPowerManager) {
-                case DISPLAY_BLANK_STATE_BLANKED:
-                    device.blankLocked();
-                    break;
-                case DISPLAY_BLANK_STATE_UNBLANKED:
-                    device.unblankLocked();
-                    break;
-            }
+            device.requestDisplayStateLocked(mGlobalDisplayState);
         }
     }
 
@@ -816,9 +796,7 @@
                     + device.getDisplayDeviceInfoLocked());
             return;
         }
-        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
-                && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
-        display.configureDisplayInTransactionLocked(device, isBlanked);
+        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
 
         // Update the viewports if needed.
         if (!mDefaultViewport.valid
@@ -897,8 +875,7 @@
             pw.println("  mOnlyCode=" + mOnlyCore);
             pw.println("  mSafeMode=" + mSafeMode);
             pw.println("  mPendingTraversal=" + mPendingTraversal);
-            pw.println("  mAllDisplayBlankStateFromPowerManager="
-                    + mAllDisplayBlankStateFromPowerManager);
+            pw.println("  mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
             pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
             pw.println("  mDefaultViewport=" + mDefaultViewport);
             pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
@@ -1322,11 +1299,26 @@
 
     private final class LocalService extends DisplayManagerInternal {
         @Override
-        public void initPowerManagement(DisplayPowerCallbacks callbacks, Handler handler,
+        public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
                 SensorManager sensorManager) {
             synchronized (mSyncRoot) {
+                DisplayBlanker blanker = new DisplayBlanker() {
+                    @Override
+                    public void requestDisplayState(int state) {
+                        // The order of operations is important for legacy reasons.
+                        if (state == Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+
+                        callbacks.onDisplayStateChange(state);
+
+                        if (state != Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+                    }
+                };
                 mDisplayPowerController = new DisplayPowerController(
-                        mContext, callbacks, handler, sensorManager);
+                        mContext, callbacks, handler, sensorManager, blanker);
             }
         }
 
@@ -1343,16 +1335,6 @@
         }
 
         @Override
-        public void blankAllDisplaysFromPowerManager() {
-            blankAllDisplaysFromPowerManagerInternal();
-        }
-
-        @Override
-        public void unblankAllDisplaysFromPowerManager() {
-            unblankAllDisplaysFromPowerManagerInternal();
-        }
-
-        @Override
         public DisplayInfo getDisplayInfo(int displayId) {
             return getDisplayInfoInternal(displayId, Process.myUid());
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 62fb02a..1f38eb6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -42,6 +42,7 @@
 import android.util.Slog;
 import android.util.Spline;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -122,6 +123,9 @@
     // The sensor manager.
     private final SensorManager mSensorManager;
 
+    // The display blanker.
+    private final DisplayBlanker mBlanker;
+
     // The proximity sensor, or null if not available or needed.
     private Sensor mProximitySensor;
 
@@ -225,13 +229,15 @@
      * Creates the display power controller.
      */
     public DisplayPowerController(Context context,
-            DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) {
+            DisplayPowerCallbacks callbacks, Handler handler,
+            SensorManager sensorManager, DisplayBlanker blanker) {
         mHandler = new DisplayControllerHandler(handler.getLooper());
         mCallbacks = callbacks;
 
         mBatteryStats = BatteryStatsService.getService();
         mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
+        mBlanker = blanker;
 
         final Resources resources = context.getResources();
 
@@ -366,8 +372,11 @@
     }
 
     private void initialize() {
-        mPowerState = new DisplayPowerState(new ElectronBeam(), mCallbacks,
-                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
+        // Initialize the power state object for the default display.
+        // In the future, we might manage multiple displays independently.
+        mPowerState = new DisplayPowerState(mBlanker,
+                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
+                new ElectronBeam(Display.DEFAULT_DISPLAY));
 
         mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
                 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -384,7 +393,7 @@
 
         // Initialize screen state for battery stats.
         try {
-            if (mPowerState.isScreenOn()) {
+            if (mPowerState.getScreenState() != Display.STATE_OFF) {
                 mBatteryStats.noteScreenOn();
             } else {
                 mBatteryStats.noteScreenOff();
@@ -523,7 +532,7 @@
         // Animate the screen on or off unless blocked.
         if (mScreenOffBecauseOfProximity) {
             // Screen off due to proximity.
-            setScreenOn(false);
+            setScreenState(Display.STATE_OFF);
             unblockScreenOn();
         } else if (mPowerRequest.wantScreenOnAny()) {
             // Want screen on.
@@ -534,7 +543,8 @@
                 // Turn the screen on.  The contents of the screen may not yet
                 // be visible if the electron beam has not been dismissed because
                 // its last frame of animation is solid black.
-                setScreenOn(true);
+                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
+                        ? Display.STATE_DOZING : Display.STATE_ON);
 
                 if (mPowerRequest.blockScreenOn
                         && mPowerState.getElectronBeamLevel() == 0.0f) {
@@ -567,12 +577,12 @@
             if (!mElectronBeamOnAnimator.isStarted()) {
                 if (!mElectronBeamOffAnimator.isStarted()) {
                     if (mPowerState.getElectronBeamLevel() == 0.0f) {
-                        setScreenOn(false);
+                        setScreenState(Display.STATE_OFF);
                     } else if (mPowerState.prepareElectronBeam(
                             mElectronBeamFadesConfig ?
                                     ElectronBeam.MODE_FADE :
                                             ElectronBeam.MODE_COOL_DOWN)
-                            && mPowerState.isScreenOn()) {
+                            && mPowerState.getScreenState() != Display.STATE_OFF) {
                         mElectronBeamOffAnimator.start();
                     } else {
                         mElectronBeamOffAnimator.end();
@@ -610,9 +620,9 @@
     private void blockScreenOn() {
         if (!mScreenOnWasBlocked) {
             mScreenOnWasBlocked = true;
+            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             if (DEBUG) {
                 Slog.d(TAG, "Blocked screen on.");
-                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             }
         }
     }
@@ -627,11 +637,11 @@
         }
     }
 
-    private void setScreenOn(boolean on) {
-        if (mPowerState.isScreenOn() != on) {
-            mPowerState.setScreenOn(on);
+    private void setScreenState(int state) {
+        if (mPowerState.getScreenState() != state) {
+            mPowerState.setScreenState(state);
             try {
-                if (on) {
+                if (state != Display.STATE_OFF) {
                     mBatteryStats.noteScreenOn();
                 } else {
                     mBatteryStats.noteScreenOff();
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index e1416d7..a5f8849 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,7 +18,6 @@
 
 import com.android.server.lights.Light;
 
-import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
@@ -27,6 +26,7 @@
 import android.util.IntProperty;
 import android.util.Slog;
 import android.view.Choreographer;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -54,12 +54,12 @@
 
     private final Handler mHandler;
     private final Choreographer mChoreographer;
-    private final ElectronBeam mElectronBeam;
-    private final DisplayPowerCallbacks mCallbacks;
+    private final DisplayBlanker mBlanker;
     private final Light mBacklight;
+    private final ElectronBeam mElectronBeam;
     private final PhotonicModulator mPhotonicModulator;
 
-    private boolean mScreenOn;
+    private int mScreenState;
     private int mScreenBrightness;
     private boolean mScreenReady;
     private boolean mScreenUpdatePending;
@@ -71,13 +71,12 @@
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(ElectronBeam electronBean,
-            DisplayPowerCallbacks callbacks, Light backlight) {
+    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
-        mElectronBeam = electronBean;
-        mCallbacks = callbacks;
+        mBlanker = blanker;
         mBacklight = backlight;
+        mElectronBeam = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
 
         // At boot time, we know that the screen is on and the electron beam
@@ -86,7 +85,7 @@
         // Although we set the brightness to full on here, the display power controller
         // will reset the brightness to a new level immediately before the changes
         // actually have a chance to be applied.
-        mScreenOn = true;
+        mScreenState = Display.STATE_ON;
         mScreenBrightness = PowerManager.BRIGHTNESS_ON;
         scheduleScreenUpdate();
 
@@ -122,25 +121,25 @@
     };
 
     /**
-     * Sets whether the screen is on or off.
+     * Sets whether the screen is on, off, or dozing.
      */
-    public void setScreenOn(boolean on) {
-        if (mScreenOn != on) {
+    public void setScreenState(int state) {
+        if (mScreenState != state) {
             if (DEBUG) {
-                Slog.d(TAG, "setScreenOn: on=" + on);
+                Slog.d(TAG, "setScreenState: state=" + state);
             }
 
-            mScreenOn = on;
+            mScreenState = state;
             mScreenReady = false;
             scheduleScreenUpdate();
         }
     }
 
     /**
-     * Returns true if the screen is on.
+     * Gets the desired screen state.
      */
-    public boolean isScreenOn() {
-        return mScreenOn;
+    public int getScreenState() {
+        return mScreenState;
     }
 
     /**
@@ -155,7 +154,7 @@
             }
 
             mScreenBrightness = brightness;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate();
             }
@@ -219,7 +218,7 @@
             }
 
             mElectronBeamLevel = level;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate(); // update backlight brightness
             }
@@ -256,7 +255,7 @@
     public void dump(PrintWriter pw) {
         pw.println();
         pw.println("Display Power State:");
-        pw.println("  mScreenOn=" + mScreenOn);
+        pw.println("  mScreenState=" + Display.stateToString(mScreenState));
         pw.println("  mScreenBrightness=" + mScreenBrightness);
         pw.println("  mScreenReady=" + mScreenReady);
         pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
@@ -302,8 +301,9 @@
         public void run() {
             mScreenUpdatePending = false;
 
-            int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
-            if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+            int brightness = mScreenState != Display.STATE_OFF
+                    && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+            if (mPhotonicModulator.setState(mScreenState, brightness)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Screen ready");
                 }
@@ -335,26 +335,26 @@
      * Updates the state of the screen and backlight asynchronously on a separate thread.
      */
     private final class PhotonicModulator {
-        private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
+        private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
         private static final int INITIAL_BACKLIGHT = -1; // unknown
 
         private final Object mLock = new Object();
 
-        private boolean mPendingOn = INITIAL_SCREEN_ON;
+        private int mPendingState = INITIAL_SCREEN_STATE;
         private int mPendingBacklight = INITIAL_BACKLIGHT;
-        private boolean mActualOn = INITIAL_SCREEN_ON;
+        private int mActualState = INITIAL_SCREEN_STATE;
         private int mActualBacklight = INITIAL_BACKLIGHT;
         private boolean mChangeInProgress;
 
-        public boolean setState(boolean on, int backlight) {
+        public boolean setState(int state, int backlight) {
             synchronized (mLock) {
-                if (on != mPendingOn || backlight != mPendingBacklight) {
+                if (state != mPendingState || backlight != mPendingBacklight) {
                     if (DEBUG) {
-                        Slog.d(TAG, "Requesting new screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Requesting new screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
 
-                    mPendingOn = on;
+                    mPendingState = state;
                     mPendingBacklight = backlight;
 
                     if (!mChangeInProgress) {
@@ -369,9 +369,9 @@
         public void dump(PrintWriter pw) {
             pw.println();
             pw.println("Photonic Modulator State:");
-            pw.println("  mPendingOn=" + mPendingOn);
+            pw.println("  mPendingState=" + Display.stateToString(mPendingState));
             pw.println("  mPendingBacklight=" + mPendingBacklight);
-            pw.println("  mActualOn=" + mActualOn);
+            pw.println("  mActualState=" + Display.stateToString(mActualState));
             pw.println("  mActualBacklight=" + mActualBacklight);
             pw.println("  mChangeInProgress=" + mChangeInProgress);
         }
@@ -381,35 +381,35 @@
             public void run() {
                 // Apply pending changes until done.
                 for (;;) {
-                    final boolean on;
-                    final boolean onChanged;
+                    final int state;
+                    final boolean stateChanged;
                     final int backlight;
                     final boolean backlightChanged;
                     synchronized (mLock) {
-                        on = mPendingOn;
-                        onChanged = (on != mActualOn);
+                        state = mPendingState;
+                        stateChanged = (state != mActualState);
                         backlight = mPendingBacklight;
                         backlightChanged = (backlight != mActualBacklight);
-                        if (!onChanged && !backlightChanged) {
+                        if (!stateChanged && !backlightChanged) {
                             mChangeInProgress = false;
                             break;
                         }
-                        mActualOn = on;
+                        mActualState = state;
                         mActualBacklight = backlight;
                     }
 
                     if (DEBUG) {
-                        Slog.d(TAG, "Updating screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Updating screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
-                    if (onChanged && on) {
-                        mCallbacks.unblankAllDisplays();
+                    if (stateChanged && state != Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                     if (backlightChanged) {
                         mBacklight.setBrightness(backlight);
                     }
-                    if (onChanged && !on) {
-                        mCallbacks.blankAllDisplays();
+                    if (stateChanged && state == Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                 }
 
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java
index 13816bb..18e4049 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ElectronBeam.java
@@ -35,7 +35,6 @@
 import android.os.Looper;
 import android.util.FloatMath;
 import android.util.Slog;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
@@ -74,6 +73,8 @@
     // See code for details.
     private static final int DEJANK_FRAMES = 3;
 
+    private final int mDisplayId;
+
     // Set to true when the animation context has been fully prepared.
     private boolean mPrepared;
     private int mMode;
@@ -118,8 +119,8 @@
      */
     public static final int MODE_FADE = 2;
 
-
-    public ElectronBeam() {
+    public ElectronBeam(int displayId) {
+        mDisplayId = displayId;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
@@ -139,7 +140,7 @@
 
         // Get the display size and layer stack.
         // This is not expected to change while the electron beam surface is showing.
-        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
@@ -528,7 +529,8 @@
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
 
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal, mSurfaceControl);
+            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+                    mDisplayId, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
@@ -687,11 +689,13 @@
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
         private final DisplayManagerInternal mDisplayManagerInternal;
+        private final int mDisplayId;
         private SurfaceControl mSurfaceControl;
 
         public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
-                SurfaceControl surfaceControl) {
+                int displayId, SurfaceControl surfaceControl) {
             mDisplayManagerInternal = displayManagerInternal;
+            mDisplayId = displayId;
             mSurfaceControl = surfaceControl;
             mDisplayManagerInternal.registerDisplayTransactionListener(this);
         }
@@ -710,8 +714,7 @@
                     return;
                 }
 
-                DisplayInfo displayInfo =
-                        mDisplayManagerInternal.getDisplayInfo(Display.DEFAULT_DISPLAY);
+                DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
                 switch (displayInfo.rotation) {
                     case Surface.ROTATION_0:
                         mSurfaceControl.setPosition(0, 0);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 02be477..2c8f1b4 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -101,7 +101,7 @@
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
-        private boolean mBlanked;
+        private int mState = Display.STATE_UNKNOWN;
 
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
                 SurfaceControl.PhysicalDisplayInfo phys) {
@@ -134,6 +134,7 @@
                 mInfo.width = mPhys.width;
                 mInfo.height = mPhys.height;
                 mInfo.refreshRate = mPhys.refreshRate;
+                mInfo.state = mState;
 
                 // Assume that all built-in displays that have secure output (eg. HDCP) also
                 // support compositing from gralloc protected buffers.
@@ -177,15 +178,16 @@
         }
 
         @Override
-        public void blankLocked() {
-            mBlanked = true;
-            SurfaceControl.blankDisplay(getDisplayTokenLocked());
-        }
-
-        @Override
-        public void unblankLocked() {
-            mBlanked = false;
-            SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+        public void requestDisplayStateLocked(int state) {
+            if (mState != state) {
+                if (state == Display.STATE_OFF && mState != Display.STATE_OFF) {
+                    SurfaceControl.blankDisplay(getDisplayTokenLocked());
+                } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) {
+                    SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+                }
+                mState = state;
+                updateDeviceInfoLocked();
+            }
         }
 
         @Override
@@ -193,7 +195,12 @@
             super.dumpLocked(pw);
             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
             pw.println("mPhys=" + mPhys);
-            pw.println("mBlanked=" + mBlanked);
+            pw.println("mState=" + Display.stateToString(mState));
+        }
+
+        private void updateDeviceInfoLocked() {
+            mInfo = null;
+            sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index c26c438..d61a35b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -114,6 +114,7 @@
                 mInfo.copyFrom(mOverrideDisplayInfo);
                 mInfo.layerStack = mBaseDisplayInfo.layerStack;
                 mInfo.name = mBaseDisplayInfo.name;
+                mInfo.state = mBaseDisplayInfo.state;
             } else {
                 mInfo.copyFrom(mBaseDisplayInfo);
             }
@@ -212,6 +213,7 @@
             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+            mBaseDisplayInfo.state = deviceInfo.state;
             mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 007acf7..bfd8372c 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -194,12 +194,14 @@
         private final int mDensityDpi;
         private final boolean mSecure;
 
-        private Surface mSurface;
+        private int mState;
         private SurfaceTexture mSurfaceTexture;
+        private Surface mSurface;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
-                int width, int height, float refreshRate, int densityDpi, boolean secure,
+                int width, int height, float refreshRate,
+                int densityDpi, boolean secure, int state,
                 SurfaceTexture surfaceTexture) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
@@ -208,6 +210,7 @@
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
             mSecure = secure;
+            mState = state;
             mSurfaceTexture = surfaceTexture;
         }
 
@@ -230,6 +233,11 @@
             }
         }
 
+        public void setStateLocked(int state) {
+            mState = state;
+            mInfo = null;
+        }
+
         @Override
         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
             if (mInfo == null) {
@@ -247,6 +255,7 @@
                 }
                 mInfo.type = Display.TYPE_OVERLAY;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+                mInfo.state = mState;
             }
             return mInfo;
         }
@@ -288,11 +297,12 @@
 
         // Called on the UI thread.
         @Override
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
             synchronized (getSyncRoot()) {
                 IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
+                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
+                        state, surfaceTexture);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -309,6 +319,17 @@
             }
         }
 
+        // Called on the UI thread.
+        @Override
+        public void onStateChanged(int state) {
+            synchronized (getSyncRoot()) {
+                if (mDevice != null) {
+                    mDevice.setStateLocked(state);
+                    sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+                }
+            }
+        }
+
         public void dumpLocked(PrintWriter pw) {
             pw.println("  " + mName + ":");
             pw.println("    mWidth=" + mWidth);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f1dd60a..06891f3 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -282,6 +282,7 @@
             if (displayId == mDefaultDisplay.getDisplayId()) {
                 if (updateDefaultDisplayInfo()) {
                     relayout();
+                    mListener.onStateChanged(mDefaultDisplayInfo.state);
                 } else {
                     dismiss();
                 }
@@ -301,7 +302,8 @@
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                 int width, int height) {
-            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
+            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
+                    mDefaultDisplayInfo.state);
         }
 
         @Override
@@ -370,7 +372,9 @@
      * Watches for significant changes in the overlay display window lifecycle.
      */
     public interface Listener {
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+        public void onWindowCreated(SurfaceTexture surfaceTexture,
+                float refreshRate, int state);
         public void onWindowDestroyed();
+        public void onStateChanged(int state);
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
index 64b51c9..baae1d99 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -182,11 +182,49 @@
     }
 
     /**
+     * Send &lt;Active Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendActiveSource(int physicalAddress) {
+        logWarning("<Active Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Inactive Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendInactiveSource(int physicalAddress) {
+        logWarning("<Inactive Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Image View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendImageViewOn() {
+        logWarning("<Image View On> not valid for the device type: " + mType);
+    }
+
+    /**
+     * Send &lt;Text View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendTextViewOn() {
+        logWarning("<Text View On> not valid for the device type: " + mType);
+    }
+
+    /**
      * Check if the connected sink device is in powered-on state. The default implementation
      * simply returns false. Should be overriden by subclass to report the correct state.
      */
     public boolean isSinkDeviceOn() {
-        Log.w(TAG, "Not valid for the device type: " + mType);
+        logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
         return false;
     }
+
+    private void logWarning(String msg) {
+        Log.w(TAG, msg);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
index 0310264..f8cf11d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -66,14 +66,11 @@
         // 1) Response for the queried power status request arrives. Update the status.
         // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
         //    into standby mode too.
-        // 3) Broadcast <Report Physical Address> command from TV, which is sent while it boots up.
         if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
             mSinkDevicePowerStatus = params[0];
         } else if (srcAddress == HdmiCec.ADDR_TV) {
             if (opcode == HdmiCec.MESSAGE_STANDBY) {
                 mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
-            } else if (opcode == HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS) {
-                mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_ON;
             }
         }
         super.handleMessage(srcAddress, dstAddress, opcode, params);
@@ -95,4 +92,38 @@
     public boolean isSinkDeviceOn() {
         return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
     }
+
+    @Override
+    public void sendActiveSource(int physicalAddress) {
+        setIsActiveSource(true);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendInactiveSource(int physicalAddress) {
+        setIsActiveSource(false);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendImageViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
+
+    @Override
+    public void sendTextViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index aa496c5..0a4c719 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -277,14 +277,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                device.setIsActiveSource(true);
-                int physicalAddress = nativeGetPhysicalAddress(mNativePtr);
-                byte[] param = new byte[] {
-                    (byte) ((physicalAddress >> 8) & 0xff),
-                    (byte) (physicalAddress & 0xff)
-                };
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
-                        HdmiCec.MESSAGE_ACTIVE_SOURCE, param);
+                device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
             }
         }
 
@@ -293,9 +286,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                device.setIsActiveSource(false);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_BROADCAST,
-                        HdmiCec.MESSAGE_INACTIVE_SOURCE, EMPTY_PARAM);
+                device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
             }
         }
 
@@ -304,8 +295,7 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
-                        HdmiCec.MESSAGE_IMAGE_VIEW_ON, EMPTY_PARAM);
+                device.sendImageViewOn();
             }
         }
 
@@ -314,8 +304,16 @@
             enforceAccessPermission();
             synchronized (mLock) {
                 HdmiCecDevice device = getLogicalDeviceLocked(b);
-                nativeSendMessage(mNativePtr, device.getType(), HdmiCec.ADDR_TV,
-                        HdmiCec.MESSAGE_TEXT_VIEW_ON, EMPTY_PARAM);
+                device.sendTextViewOn();
+            }
+        }
+
+        public void sendGiveDevicePowerStatus(IBinder b, int address) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                nativeSendMessage(mNativePtr, device.getType(), address,
+                        HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
             }
         }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 316bd57..54cb035 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -185,6 +185,7 @@
             InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
+    private static native void nativeSetInteractive(long ptr, boolean interactive);
     private static native void nativeReloadCalibration(long ptr);
     private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
             int repeat, int token);
@@ -1404,14 +1405,13 @@
     }
 
     // Native callback.
-    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
-                event, policyFlags, isScreenOn);
+    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     // Native callback.
-    private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+    private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
                 whenNanos, policyFlags);
     }
 
@@ -1570,9 +1570,9 @@
         public long notifyANR(InputApplicationHandle inputApplicationHandle,
                 InputWindowHandle inputWindowHandle, String reason);
 
-        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
-        public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
+        public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
         public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                 KeyEvent event, int policyFlags);
@@ -1740,5 +1740,10 @@
         public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
             return injectInputEventInternal(event, displayId, mode);
         }
+
+        @Override
+        public void setInteractive(boolean interactive) {
+            nativeSetInteractive(mPtr, interactive);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index eb7cc4c..855ae23 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1730,7 +1730,7 @@
     private void updateScreenOn() {
         synchronized (mRulesLock) {
             try {
-                mScreenOn = mPowerManager.isScreenOn();
+                mScreenOn = mPowerManager.isInteractive();
             } catch (RemoteException e) {
                 // ignored; service lives in system_server
             }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index f72efff..d84e8e1 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -28,6 +28,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.input.InputManagerInternal;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -86,6 +87,7 @@
     private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
     private final ActivityManagerInternal mActivityManagerInternal;
+    private final InputManagerInternal mInputManagerInternal;
 
     private final NotifierHandler mHandler;
     private final Intent mScreenOnIntent;
@@ -121,6 +123,7 @@
         mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
 
         mHandler = new NotifierHandler(looper);
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -232,73 +235,58 @@
     }
 
     /**
-     * Called when the device is waking up from sleep and the
-     * display is about to be turned on.
+     * Notifies that the device is changing interactive state.
      */
-    public void onWakeUpStarted() {
+    public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUpStarted");
+            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+                    + ", reason=" + reason);
         }
 
         synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_AWAKE) {
-                mActualPowerState = POWER_STATE_AWAKE;
-                mPendingWakeUpBroadcast = true;
-                if (!mScreenOnBlockerAcquired) {
-                    mScreenOnBlockerAcquired = true;
-                    mScreenOnBlocker.acquire();
+            if (interactive) {
+                // Waking up...
+                if (mActualPowerState != POWER_STATE_AWAKE) {
+                    mActualPowerState = POWER_STATE_AWAKE;
+                    mPendingWakeUpBroadcast = true;
+                    if (!mScreenOnBlockerAcquired) {
+                        mScreenOnBlockerAcquired = true;
+                        mScreenOnBlocker.acquire();
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
+            } else {
+                // Going to sleep...
+                mLastGoToSleepReason = reason;
             }
+            mInputManagerInternal.setInteractive(interactive);
         }
     }
 
     /**
-     * Called when the device has finished waking up from sleep
-     * and the display has been turned on.
+     * Notifies that the device has finished changing interactive state.
      */
-    public void onWakeUpFinished() {
+    public void onInteractiveStateChangeFinished(boolean interactive) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUpFinished");
-        }
-    }
-
-    /**
-     * Called when the device is going to sleep.
-     */
-    public void onGoToSleepStarted(int reason) {
-        if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepStarted");
+            Slog.d(TAG, "onInteractiveChangeFinished");
         }
 
         synchronized (mLock) {
-            mLastGoToSleepReason = reason;
-        }
-    }
-
-    /**
-     * Called when the device has finished going to sleep and the
-     * display has been turned off.
-     *
-     * This is a good time to make transitions that we don't want the user to see,
-     * such as bringing the key guard to focus.  There's no guarantee for this,
-     * however because the user could turn the device on again at any time.
-     * Some things may need to be protected by other mechanisms that defer screen on.
-     */
-    public void onGoToSleepFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepFinished");
-        }
-
-        synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_ASLEEP) {
-                mActualPowerState = POWER_STATE_ASLEEP;
-                mPendingGoToSleepBroadcast = true;
-                if (mUserActivityPending) {
-                    mUserActivityPending = false;
-                    mHandler.removeMessages(MSG_USER_ACTIVITY);
+            if (!interactive) {
+                // Finished going to sleep...
+                // This is a good time to make transitions that we don't want the user to see,
+                // such as bringing the key guard to focus.  There's no guarantee for this,
+                // however because the user could turn the device on again at any time.
+                // Some things may need to be protected by other mechanisms that defer screen on.
+                if (mActualPowerState != POWER_STATE_ASLEEP) {
+                    mActualPowerState = POWER_STATE_ASLEEP;
+                    mPendingGoToSleepBroadcast = true;
+                    if (mUserActivityPending) {
+                        mUserActivityPending = false;
+                        mHandler.removeMessages(MSG_USER_ACTIVITY);
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 90363d7..82cef7f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -62,6 +62,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.view.Display;
 import android.view.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
@@ -209,6 +210,10 @@
     // A bitfield that summarizes the state of all active wakelocks.
     private int mWakeLockSummary;
 
+    // True if the device is in an interactive state.
+    private boolean mInteractive;
+    private boolean mInteractiveChanging;
+
     // If true, instructs the display controller to wait for the proximity sensor to
     // go negative before turning the screen on.
     private boolean mRequestWaitForNegativeProximity;
@@ -217,11 +222,6 @@
     private long mLastWakeTime;
     private long mLastSleepTime;
 
-    // True if we need to send a wake up or go to sleep finished notification
-    // when the display is ready.
-    private boolean mSendWakeUpFinishedNotificationWhenReady;
-    private boolean mSendGoToSleepFinishedNotificationWhenReady;
-
     // Timestamp of the last call to user activity.
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
@@ -265,11 +265,11 @@
 
     // True if auto-suspend mode is enabled.
     // Refer to autosuspend.h.
-    private boolean mAutoSuspendModeEnabled;
+    private boolean mHalAutoSuspendModeEnabled;
 
     // True if interactive mode is enabled.
     // Refer to power.h.
-    private boolean mInteractiveModeEnabled;
+    private boolean mHalInteractiveModeEnabled;
 
     // True if the device is plugged into a power source.
     private boolean mIsPowered;
@@ -289,10 +289,10 @@
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
     // True to decouple auto-suspend mode from the display state.
-    private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+    private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
 
     // True to decouple interactive mode from the display state.
-    private boolean mDecoupleInteractiveModeFromDisplayConfig;
+    private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
 
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -397,7 +397,6 @@
 
     private native void nativeInit();
 
-    private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
     private static native void nativeAcquireSuspendBlocker(String name);
     private static native void nativeReleaseSuspendBlocker(String name);
     private static native void nativeSetInteractive(boolean enable);
@@ -412,13 +411,17 @@
             mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
             mDisplaySuspendBlocker.acquire();
             mHoldingDisplaySuspendBlocker = true;
+            mHalAutoSuspendModeEnabled = false;
+            mHalInteractiveModeEnabled = true;
 
             mScreenOnBlocker = new ScreenOnBlockerImpl();
             mWakefulness = WAKEFULNESS_AWAKE;
-        }
+            mInteractive = true;
 
-        nativeInit();
-        nativeSetPowerState(true, true);
+            nativeInit();
+            nativeSetAutoSuspend(false);
+            nativeSetInteractive(true);
+        }
     }
 
     @Override
@@ -446,14 +449,6 @@
 
         Watchdog.getInstance().addMonitor(this);
         Watchdog.getInstance().addThread(mHandler);
-
-        // Forcibly turn the screen on at boot so that it is in a known power state.
-        // We do this in init() rather than in the constructor because setting the
-        // screen state requires a call into surface flinger which then needs to call back
-        // into the activity manager to check permissions.  Unfortunately the
-        // activity manager is not running when the constructor is called, so we
-        // have to defer setting the screen state until this point.
-        mDisplayPowerCallbacks.unblankAllDisplays();
     }
 
     void setPolicy(WindowManagerPolicy policy) {
@@ -547,9 +542,9 @@
     private void readConfigurationLocked() {
         final Resources resources = mContext.getResources();
 
-        mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+        mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
-        mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+        mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
@@ -867,11 +862,6 @@
         return false;
     }
 
-    // Called from native code.
-    private void wakeUpFromNative(long eventTime) {
-        wakeUpInternal(eventTime);
-    }
-
     private void wakeUpInternal(long eventTime) {
         synchronized (mLock) {
             if (wakeUpNoUpdateLocked(eventTime)) {
@@ -902,26 +892,16 @@
                 break;
         }
 
-        if (mWakefulness != WAKEFULNESS_DREAMING) {
-            sendPendingNotificationsLocked();
-            mNotifier.onWakeUpStarted();
-            mSendWakeUpFinishedNotificationWhenReady = true;
-        }
-
         mLastWakeTime = eventTime;
-        mWakefulness = WAKEFULNESS_AWAKE;
         mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_AWAKE;
+        setInteractiveStateLocked(true, 0);
 
         userActivityNoUpdateLocked(
                 eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
         return true;
     }
 
-    // Called from native code.
-    private void goToSleepFromNative(long eventTime, int reason) {
-        goToSleepInternal(eventTime, reason);
-    }
-
     private void goToSleepInternal(long eventTime, int reason) {
         synchronized (mLock) {
             if (goToSleepNoUpdateLocked(eventTime, reason)) {
@@ -958,14 +938,11 @@
                 break;
         }
 
-        sendPendingNotificationsLocked();
-        mNotifier.onGoToSleepStarted(reason);
-        mSendGoToSleepFinishedNotificationWhenReady = true;
-
         mLastSleepTime = eventTime;
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_DOZING;
         mSandmanSummoned = true;
+        setInteractiveStateLocked(false, reason);
 
         // Report the number of wake locks that will be cleared by going to sleep.
         int numWakeLocksCleared = 0;
@@ -1007,6 +984,7 @@
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_DREAMING;
         mSandmanSummoned = true;
+        setInteractiveStateLocked(true, 0);
         return true;
     }
 
@@ -1025,9 +1003,27 @@
 
         mDirty |= DIRTY_WAKEFULNESS;
         mWakefulness = WAKEFULNESS_ASLEEP;
+        setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
         return true;
     }
 
+    private void setInteractiveStateLocked(boolean interactive, int reason) {
+        if (mInteractive != interactive) {
+            finishInteractiveStateChangeLocked();
+
+            mInteractive = interactive;
+            mInteractiveChanging = true;
+            mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+        }
+    }
+
+    private void finishInteractiveStateChangeLocked() {
+        if (mInteractiveChanging) {
+            mNotifier.onInteractiveStateChangeFinished(mInteractive);
+            mInteractiveChanging = false;
+        }
+    }
+
     /**
      * Updates the global power state based on dirty bits recorded in mDirty.
      *
@@ -1071,7 +1067,7 @@
 
         // Phase 3: Send notifications, if needed.
         if (mDisplayReady) {
-            sendPendingNotificationsLocked();
+            finishInteractiveStateChangeLocked();
         }
 
         // Phase 4: Update suspend blocker.
@@ -1080,17 +1076,6 @@
         updateSuspendBlockerLocked();
     }
 
-    private void sendPendingNotificationsLocked() {
-        if (mSendWakeUpFinishedNotificationWhenReady) {
-            mSendWakeUpFinishedNotificationWhenReady = false;
-            mNotifier.onWakeUpFinished();
-        }
-        if (mSendGoToSleepFinishedNotificationWhenReady) {
-            mSendGoToSleepFinishedNotificationWhenReady = false;
-            mNotifier.onGoToSleepFinished();
-        }
-    }
-
     /**
      * Updates the value of mIsPowered.
      * Sets DIRTY_IS_POWERED if a change occurred.
@@ -1210,48 +1195,45 @@
                         mWakeLockSummary |= WAKE_LOCK_CPU;
                         break;
                     case PowerManager.FULL_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU
-                                    | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
                         break;
                     case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
                         break;
                     case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
-                        }
-                        if (mWakefulness == WAKEFULNESS_AWAKE) {
-                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
                         break;
                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_AWAKE
-                                || mWakefulness == WAKEFULNESS_DREAMING
-                                || mWakefulness == WAKEFULNESS_DOZING) {
-                            mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                         break;
                     case PowerManager.DOZE_WAKE_LOCK:
-                        if (mWakefulness == WAKEFULNESS_DOZING) {
-                            mWakeLockSummary |= WAKE_LOCK_DOZE;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_DOZE;
                         break;
                 }
             }
 
+            // Cancel wake locks that make no sense based on the current state.
+            if (mWakefulness != WAKEFULNESS_DOZING) {
+                mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+            }
+            if (mWakefulness == WAKEFULNESS_ASLEEP
+                    || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+                mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
+                        | WAKE_LOCK_BUTTON_BRIGHT);
+                if (mWakefulness == WAKEFULNESS_ASLEEP) {
+                    mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+                }
+            }
+
+            // Infer implied wake locks where necessary based on the current state.
+            if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
+                if (mWakefulness == WAKEFULNESS_AWAKE) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
+                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU;
+                }
+            }
+
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
                         + wakefulnessToString(mWakefulness)
@@ -1269,12 +1251,14 @@
      */
     private void updateUserActivitySummaryLocked(long now, int dirty) {
         // Update the status of the user activity timeout timer.
-        if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
             mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
 
             long nextTimeout = 0;
             if (mWakefulness == WAKEFULNESS_AWAKE
-                    || mWakefulness == WAKEFULNESS_DREAMING) {
+                    || mWakefulness == WAKEFULNESS_DREAMING
+                    || mWakefulness == WAKEFULNESS_DOZING) {
                 final int screenOffTimeout = getScreenOffTimeoutLocked();
                 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
 
@@ -1598,8 +1582,6 @@
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
             final int newScreenState = getDesiredScreenPowerStateLocked();
             mDisplayPowerRequest.screenState = newScreenState;
-            nativeSetPowerState(isScreenOnLocked(),
-                    newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
 
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1681,7 +1663,7 @@
 
     private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
             new DisplayManagerInternal.DisplayPowerCallbacks() {
-        private boolean mBlanked;
+        private int mDisplayState = Display.STATE_UNKNOWN;
 
         @Override
         public void onStateChanged() {
@@ -1712,6 +1694,33 @@
         }
 
         @Override
+        public void onDisplayStateChange(int state) {
+            // This method is only needed to support legacy display blanking behavior
+            // where the display's power state is coupled to suspend or to the power HAL.
+            // The order of operations matters here.
+            synchronized (mLock) {
+                if (mDisplayState != state) {
+                    mDisplayState = state;
+                    if (state == Display.STATE_OFF) {
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(false);
+                        }
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(true);
+                        }
+                    } else {
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(false);
+                        }
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(true);
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
         public void acquireSuspendBlocker() {
             mDisplaySuspendBlocker.acquire();
         }
@@ -1722,37 +1731,9 @@
         }
 
         @Override
-        public void blankAllDisplays() {
-            synchronized (this) {
-                mBlanked = true;
-                mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
-                if (!mDecoupleInteractiveModeFromDisplayConfig) {
-                    setInteractiveModeLocked(false);
-                }
-                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
-                    setAutoSuspendModeLocked(true);
-                }
-            }
-        }
-
-        @Override
-        public void unblankAllDisplays() {
-            synchronized (this) {
-                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
-                    setAutoSuspendModeLocked(false);
-                }
-                if (!mDecoupleInteractiveModeFromDisplayConfig) {
-                    setInteractiveModeLocked(true);
-                }
-                mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
-                mBlanked = false;
-            }
-        }
-
-        @Override
         public String toString() {
             synchronized (this) {
-                return "blanked=" + mBlanked;
+                return "state=" + Display.stateToString(mDisplayState);
             }
         }
     };
@@ -1773,11 +1754,11 @@
 
         // Disable auto-suspend if needed.
         if (!autoSuspend) {
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(false);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(false);
             }
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(true);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(true);
             }
         }
 
@@ -1803,11 +1784,11 @@
 
         // Enable auto-suspend if needed.
         if (autoSuspend) {
-            if (mDecoupleInteractiveModeFromDisplayConfig) {
-                setInteractiveModeLocked(false);
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(false);
             }
-            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
-                setAutoSuspendModeLocked(true);
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(true);
             }
         }
     }
@@ -1834,42 +1815,32 @@
         return false;
     }
 
-    private void setAutoSuspendModeLocked(boolean enable) {
-        if (enable != mAutoSuspendModeEnabled) {
+    private void setHalAutoSuspendModeLocked(boolean enable) {
+        if (enable != mHalAutoSuspendModeEnabled) {
             if (DEBUG) {
-                Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+                Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
             }
-            mAutoSuspendModeEnabled = enable;
+            mHalAutoSuspendModeEnabled = enable;
             nativeSetAutoSuspend(enable);
         }
     }
 
-    private void setInteractiveModeLocked(boolean enable) {
-        if (enable != mInteractiveModeEnabled) {
+    private void setHalInteractiveModeLocked(boolean enable) {
+        if (enable != mHalInteractiveModeEnabled) {
             if (DEBUG) {
-                Slog.d(TAG, "Setting interactive mode to " + enable);
+                Slog.d(TAG, "Setting HAL interactive mode to " + enable);
             }
-            mInteractiveModeEnabled = enable;
+            mHalInteractiveModeEnabled = enable;
             nativeSetInteractive(enable);
         }
     }
 
-    private boolean isScreenOnInternal() {
+    private boolean isInteractiveInternal() {
         synchronized (mLock) {
-            // XXX This is a temporary hack to let certain parts of the system pretend the
-            // screen is still on even when dozing and we would normally want to report
-            // screen off.  Will be removed when the window manager is modified to use
-            // the true blanking state of the display.
-            return isScreenOnLocked()
-                    || mWakefulness == WAKEFULNESS_DOZING;
+            return mInteractive;
         }
     }
 
-    private boolean isScreenOnLocked() {
-        return mWakefulness == WAKEFULNESS_AWAKE
-                || mWakefulness == WAKEFULNESS_DREAMING;
-    }
-
     private void handleBatteryStateChangedLocked() {
         mDirty |= DIRTY_BATTERY_STATE;
         updatePowerStateLocked();
@@ -2090,6 +2061,7 @@
             pw.println("Power Manager State:");
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
             pw.println("  mWakefulness=" + wakefulnessToString(mWakefulness));
+            pw.println("  mInteractive=" + mInteractive);
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mBatteryLevel=" + mBatteryLevel);
@@ -2099,8 +2071,8 @@
             pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
             pw.println("  mSystemReady=" + mSystemReady);
-            pw.println("  mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
-            pw.println("  mInteactiveModeEnabled=" + mInteractiveModeEnabled);
+            pw.println("  mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
+            pw.println("  mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
             pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
@@ -2108,10 +2080,6 @@
             pw.println("  mSandmanSummoned=" + mSandmanSummoned);
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
-            pw.println("  mSendWakeUpFinishedNotificationWhenReady="
-                    + mSendWakeUpFinishedNotificationWhenReady);
-            pw.println("  mSendGoToSleepFinishedNotificationWhenReady="
-                    + mSendGoToSleepFinishedNotificationWhenReady);
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
             pw.println("  mLastUserActivityTimeNoChangeLights="
                     + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
@@ -2121,10 +2089,10 @@
 
             pw.println();
             pw.println("Settings and Configuration:");
-            pw.println("  mDecoupleAutoSuspendModeFromDisplayConfig="
-                    + mDecoupleAutoSuspendModeFromDisplayConfig);
-            pw.println("  mDecoupleInteractiveModeFromDisplayConfig="
-                    + mDecoupleInteractiveModeFromDisplayConfig);
+            pw.println("  mDecoupleHalAutoSuspendModeFromDisplayConfig="
+                    + mDecoupleHalAutoSuspendModeFromDisplayConfig);
+            pw.println("  mDecoupleHalInteractiveModeFromDisplayConfig="
+                    + mDecoupleHalInteractiveModeFromDisplayConfig);
             pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                     + mWakeUpWhenPluggedOrUnpluggedConfig);
             pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
@@ -2725,10 +2693,10 @@
         }
 
         @Override // Binder call
-        public boolean isScreenOn() {
+        public boolean isInteractive() {
             final long ident = Binder.clearCallingIdentity();
             try {
-                return isScreenOnInternal();
+                return isInteractiveInternal();
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4aae5c1..f02c0e6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -284,7 +284,7 @@
                 final boolean hasFocus = (child == mInputFocus);
                 final boolean isVisible = child.isVisibleLw();
                 final boolean hasWallpaper = (child == mService.mWallpaperTarget)
-                        && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
+                        && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0;
                 final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
 
                 // If there's a drag in progress and 'child' is a potential drop target,
@@ -355,17 +355,16 @@
     /* Provides an opportunity for the window manager policy to intercept early key
      * processing as soon as the key has been read from the device. */
     @Override
-    public int interceptKeyBeforeQueueing(
-            KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to intercept early
      * motion event processing when the screen is off since these events are normally
      * dropped. */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
-        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b12ae4f..ad256c8f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -24,6 +24,7 @@
 import android.util.TimeUtils;
 import android.view.IWindowId;
 
+import android.view.WindowContentFrameStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.policy.impl.PhoneWindowManager;
@@ -626,6 +627,8 @@
 
     private final PointerEventDispatcher mPointerEventDispatcher;
 
+    private WindowContentFrameStats mTempWindowRenderStats;
+
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -1890,7 +1893,9 @@
                 int insertionIndex = 0;
                 if (visible && foundW != null) {
                     final int type = foundW.mAttrs.type;
-                    if (type == TYPE_KEYGUARD || type == TYPE_KEYGUARD_SCRIM) {
+                    final int privateFlags = foundW.mAttrs.privateFlags;
+                    if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
+                            || type == TYPE_KEYGUARD_SCRIM) {
                         insertionIndex = windows.indexOf(foundW);
                     }
                 }
@@ -5288,6 +5293,13 @@
         performEnableScreen();
     }
 
+    @Override
+    public void enableScreenIfNeeded() {
+        synchronized (mWindowMap) {
+            enableScreenIfNeededLocked();
+        }
+    }
+
     void enableScreenIfNeededLocked() {
         if (DEBUG_BOOT) {
             RuntimeException here = new RuntimeException("here");
@@ -5352,18 +5364,6 @@
                 final int N = windows.size();
                 for (int i=0; i<N; i++) {
                     WindowState w = windows.get(i);
-                    if (w.mAttrs.type == TYPE_KEYGUARD) {
-                        // Only if there is a keyguard attached to the window manager
-                        // will we consider ourselves as having a keyguard.  If it
-                        // isn't attached, we don't know if it wants to be shown or
-                        // hidden.  If it is attached, we will say we have a keyguard
-                        // if the window doesn't want to be visible, because in that
-                        // case it explicitly doesn't want to be shown so we should
-                        // not delay turning the screen on for it.
-                        boolean vis = w.mViewVisibility == View.VISIBLE
-                                && w.mPolicyVisibility;
-                        haveKeyguard = !vis;
-                    }
                     if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
                         return;
                     }
@@ -5374,8 +5374,8 @@
                             haveApp = true;
                         } else if (w.mAttrs.type == TYPE_WALLPAPER) {
                             haveWallpaper = true;
-                        } else if (w.mAttrs.type == TYPE_KEYGUARD) {
-                            haveKeyguard = true;
+                        } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
+                            haveKeyguard = mPolicy.isKeyguardDrawnLw();
                         }
                     }
                 }
@@ -6981,7 +6981,6 @@
             if (mDisplayEnabled) {
                 mInputMonitor.setEventDispatchingLw(enabled);
             }
-            sendScreenStatusToClientsLocked();
         }
     }
 
@@ -7086,23 +7085,6 @@
         mPolicy.systemReady();
     }
 
-    // TODO(multidisplay): Call isScreenOn for each display.
-    private void sendScreenStatusToClientsLocked() {
-        final boolean on = mPowerManager.isScreenOn();
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-            final int numWindows = windows.size();
-            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                try {
-                    windows.get(winNdx).mClient.dispatchScreenState(on);
-                } catch (RemoteException e) {
-                    // Ignored
-                }
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Async Handler
     // -------------------------------------------------------------
@@ -8350,7 +8332,7 @@
             // just don't display").
             if (!gone || !win.mHaveFrame || win.mLayoutNeeded
                     || ((win.isConfigChanged() || win.setInsetsChanged()) &&
-                            (win.mAttrs.type == TYPE_KEYGUARD ||
+                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
                             win.mAppToken != null && win.mAppToken.layoutConfigChanges))
                     || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                 if (!win.mLayoutAttached) {
@@ -8890,8 +8872,8 @@
             if (canBeSeen
                     && (type == TYPE_SYSTEM_DIALOG
                      || type == TYPE_RECENTS_OVERLAY
-                     || type == TYPE_KEYGUARD
-                     || type == TYPE_SYSTEM_ERROR)) {
+                     || type == TYPE_SYSTEM_ERROR
+                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
                 mInnerFields.mSyswin = true;
             }
 
@@ -8904,7 +8886,7 @@
                     // content on secondary displays (by forcibly enabling mirroring unless
                     // there is other content we want to show) but still allow opaque
                     // keyguard dialogs to be shown.
-                    if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
+                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                         mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
                     }
                     mInnerFields.mDisplayHasContent = true;
@@ -10264,6 +10246,51 @@
         return mSafeMode;
     }
 
+    @Override
+    public boolean clearWindowContentFrameStats(IBinder token) {
+        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
+                "clearWindowContentFrameStats()")) {
+            throw new SecurityException("Requires FRAME_STATS permission");
+        }
+        synchronized (mWindowMap) {
+            WindowState windowState = mWindowMap.get(token);
+            if (windowState == null) {
+                return false;
+            }
+            SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl;
+            if (surfaceControl == null) {
+                return false;
+            }
+            return surfaceControl.clearContentFrameStats();
+        }
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(IBinder token) {
+        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
+                "getWindowContentFrameStats()")) {
+            throw new SecurityException("Requires FRAME_STATS permission");
+        }
+        synchronized (mWindowMap) {
+            WindowState windowState = mWindowMap.get(token);
+            if (windowState == null) {
+                return null;
+            }
+            SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl;
+            if (surfaceControl == null) {
+                return null;
+            }
+            if (mTempWindowRenderStats == null) {
+                mTempWindowRenderStats = new WindowContentFrameStats();
+            }
+            WindowContentFrameStats stats = mTempWindowRenderStats;
+            if (!surfaceControl.getContentFrameStats(stats)) {
+                return null;
+            }
+            return stats;
+        }
+    }
+
     void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
         pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
         mPolicy.dump("    ", pw, args);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index dff75ef..4318b0e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -23,12 +23,12 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.app.AppOpsManager;
@@ -1010,7 +1010,7 @@
                 && (mConfiguration == null
                         || (mConfiguration.diff(mService.mCurConfiguration) != 0));
 
-        if (mAttrs.type == TYPE_KEYGUARD) {
+        if ((mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
             // Retain configuration changed status until resetConfiguration called.
             mConfigHasChanged |= configChanged;
             configChanged = mConfigHasChanged;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index a00aaa8..54c9755 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -204,6 +204,11 @@
     } else {
         ALOGV("Logical Address Allocation success: %d", addr);
         mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
+
+        // Broadcast <Report Physical Address> when a new logical address was allocated to let
+        // other devices discover the new logical device and its logical - physical address
+        // association.
+        sendReportPhysicalAddress();
     }
     return addr;
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b3247ff..4085991 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -71,7 +71,7 @@
     jmethodID notifyANR;
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
-    jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+    jmethodID interceptWakeMotionBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID dispatchUnhandledKey;
     jmethodID checkInjectEventsPermission;
@@ -189,6 +189,7 @@
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
     void setShowTouches(bool enabled);
+    void setInteractive(bool interactive);
     void reloadCalibration();
 
     /* --- InputReaderPolicyInterface implementation --- */
@@ -214,7 +215,6 @@
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
-    virtual bool isKeyRepeatEnabled();
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
     virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
     virtual nsecs_t interceptKeyBeforeDispatching(
@@ -262,14 +262,12 @@
         wp<PointerController> pointerController;
     } mLocked;
 
+    volatile bool mInteractive;
+
     void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
     void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
     void ensureSpriteControllerLocked();
 
-    // Power manager interactions.
-    bool isScreenOn();
-    bool isScreenBright();
-
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -281,7 +279,7 @@
 
 NativeInputManager::NativeInputManager(jobject contextObj,
         jobject serviceObj, const sp<Looper>& looper) :
-        mLooper(looper) {
+        mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
     mContextObj = env->NewGlobalRef(contextObj);
@@ -637,11 +635,6 @@
     }
 }
 
-bool NativeInputManager::isKeyRepeatEnabled() {
-    // Only enable automatic key repeating when the screen is on.
-    return isScreenOn();
-}
-
 void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
     Vector<sp<InputWindowHandle> > windowHandles;
 
@@ -753,19 +746,15 @@
             InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 }
 
+void NativeInputManager::setInteractive(bool interactive) {
+    mInteractive = interactive;
+}
+
 void NativeInputManager::reloadCalibration() {
     mInputManager->getReader()->requestRefreshConfiguration(
             InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION);
 }
 
-bool NativeInputManager::isScreenOn() {
-    return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
-    return android_server_PowerManagerService_isScreenBright();
-}
-
 TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
         JNIEnv *env, jfloatArray matrixArr) {
     ScopedFloatArrayRO matrix(env, matrixArr);
@@ -841,18 +830,18 @@
     // - Ignore untrusted events and pass them along.
     // - Ask the window manager what to do with normal events and trusted injected events.
     // - For normal events wake and brighten the screen if currently off or dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED)) {
         nsecs_t when = keyEvent->getEventTime();
-        bool isScreenOn = this->isScreenOn();
-        bool isScreenBright = this->isScreenBright();
-
         JNIEnv* env = jniEnv();
         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
         jint wmActions;
         if (keyEventObj) {
             wmActions = env->CallIntMethod(mServiceObj,
                     gServiceClassInfo.interceptKeyBeforeQueueing,
-                    keyEventObj, policyFlags, isScreenOn);
+                    keyEventObj, policyFlags);
             if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                 wmActions = 0;
             }
@@ -863,16 +852,6 @@
             wmActions = 0;
         }
 
-        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
-            if (!isScreenOn) {
-                policyFlags |= POLICY_FLAG_WOKE_HERE;
-            }
-
-            if (!isScreenBright) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        }
-
         handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
     } else {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
@@ -885,24 +864,22 @@
     // - No special filtering for injected events required at this time.
     // - Filter normal events based on screen state.
     // - For normal events brighten (but do not wake) the screen if currently dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
-        if (isScreenOn()) {
+        if (policyFlags & POLICY_FLAG_INTERACTIVE) {
             policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
-            if (!isScreenBright()) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        } else {
+        } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) {
             JNIEnv* env = jniEnv();
             jint wmActions = env->CallIntMethod(mServiceObj,
-                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
+                        gServiceClassInfo.interceptWakeMotionBeforeQueueing,
                         when, policyFlags);
             if (checkAndClearExceptionFromCallback(env,
-                    "interceptMotionBeforeQueueingWhenScreenOff")) {
+                    "interceptWakeMotionBeforeQueueing")) {
                 wmActions = 0;
             }
 
-            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
             handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
         }
     } else {
@@ -1285,6 +1262,13 @@
     im->setShowTouches(enabled);
 }
 
+static void nativeSetInteractive(JNIEnv* env,
+        jclass clazz, jlong ptr, jboolean interactive) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->setInteractive(interactive);
+}
+
 static void nativeReloadCalibration(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
     im->reloadCalibration();
@@ -1395,6 +1379,8 @@
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
             (void*) nativeSetShowTouches },
+    { "nativeSetInteractive", "(JZ)V",
+            (void*) nativeSetInteractive },
     { "nativeReloadCalibration", "(J)V",
             (void*) nativeReloadCalibration },
     { "nativeVibrate", "(JI[JII)V",
@@ -1453,11 +1439,10 @@
             "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
-            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
 
-    GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-            clazz,
-            "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
+    GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz,
+            "interceptWakeMotionBeforeQueueing", "(JI)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index dbf5439..33e0bd7 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -42,8 +42,6 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jmethodID wakeUpFromNative;
-    jmethodID goToSleepFromNative;
     jmethodID userActivityFromNative;
 } gPowerManagerServiceClassInfo;
 
@@ -52,10 +50,6 @@
 static jobject gPowerManagerServiceObj;
 static struct power_module* gPowerModule;
 
-static Mutex gPowerManagerLock;
-static bool gScreenOn;
-static bool gScreenBright;
-
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
 
 // Throttling interval for user activity calls.
@@ -73,16 +67,6 @@
     return false;
 }
 
-bool android_server_PowerManagerService_isScreenOn() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenOn;
-}
-
-bool android_server_PowerManagerService_isScreenBright() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenBright;
-}
-
 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
     // Tell the power HAL when user activity occurs.
     if (gPowerModule && gPowerModule->powerHint) {
@@ -114,28 +98,6 @@
     }
 }
 
-void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.wakeUpFromNative,
-                nanoseconds_to_milliseconds(eventTime));
-        checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
-    }
-}
-
-void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.goToSleepFromNative,
-                nanoseconds_to_milliseconds(eventTime), 0);
-        checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static void nativeInit(JNIEnv* env, jobject obj) {
@@ -150,13 +112,6 @@
     }
 }
 
-static void nativeSetPowerState(JNIEnv* env,
-        jclass clazz, jboolean screenOn, jboolean screenBright) {
-    AutoMutex _l(gPowerManagerLock);
-    gScreenOn = screenOn;
-    gScreenBright = screenBright;
-}
-
 static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
     ScopedUtfChars name(env, nameStr);
     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
@@ -207,8 +162,6 @@
     /* name, signature, funcPtr */
     { "nativeInit", "()V",
             (void*) nativeInit },
-    { "nativeSetPowerState", "(ZZ)V",
-            (void*) nativeSetPowerState },
     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
             (void*) nativeAcquireSuspendBlocker },
     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
@@ -243,12 +196,6 @@
     jclass clazz;
     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
-            "wakeUpFromNative", "(J)V");
-
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
-            "goToSleepFromNative", "(JI)V");
-
     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
             "userActivityFromNative", "(JII)V");
 
@@ -256,8 +203,6 @@
     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
         gLastEventTime[i] = LLONG_MIN;
     }
-    gScreenOn = true;
-    gScreenBright = true;
     gPowerManagerServiceObj = NULL;
     gPowerModule = NULL;
     return 0;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index b48e546..f5fd3d6 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,11 +24,7 @@
 
 namespace android {
 
-extern bool android_server_PowerManagerService_isScreenOn();
-extern bool android_server_PowerManagerService_isScreenBright();
 extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
-extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
-extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
 
 } // namespace android
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 983ca2d..35f9314 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2888,6 +2888,32 @@
     }
 
     @Override
+    public void setProfileEnabled(ComponentName who) {
+        if (!mHasFeature) {
+            return;
+        }
+        synchronized (this) {
+            // Check for permissions
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            // Check if this is the profile owner who is calling
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            Slog.d(LOG_TAG, "Enabling the profile for: " + UserHandle.getCallingUserId());
+            long id = Binder.clearCallingIdentity();
+
+            try {
+                Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
+                intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    @Override
     public String getProfileOwner(int userHandle) {
         if (!mHasFeature) {
             return null;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 8b9f718..8392672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -216,7 +216,7 @@
         expectLastCall().atLeastOnce();
 
         // expect to answer screen status during systemReady()
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
         expectCurrentTime();
 
@@ -331,7 +331,7 @@
         verifyAndReset();
 
         // now turn screen off and verify REJECT rule
-        expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
@@ -341,7 +341,7 @@
         verifyAndReset();
 
         // and turn screen back on, verify ALLOW rule restored
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 502ee18..f5ac178 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -590,14 +590,19 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 intent.putExtra("state", (enabled ? 1 : 0));
                 if (enabled) {
+                    Scanner scanner = null;
                     try {
-                        Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
+                        scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
                         int card = scanner.nextInt();
                         int device = scanner.nextInt();
                         intent.putExtra("card", card);
                         intent.putExtra("device", device);
                     } catch (FileNotFoundException e) {
                         Slog.e(TAG, "could not open audio source PCM file", e);
+                    } finally {
+                        if (scanner != null) {
+                            scanner.close();
+                        }
                     }
                 }
                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7ae5460..8b54264 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
@@ -25,11 +26,16 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.Slog;
 
+import com.android.alsascan.AlsaCardsParser;
+import com.android.alsascan.AlsaDevicesParser;
 import com.android.internal.annotations.GuardedBy;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -39,7 +45,7 @@
  */
 public class UsbHostManager {
     private static final String TAG = UsbHostManager.class.getSimpleName();
-    private static final boolean LOG = false;
+    private static final boolean DEBUG_AUDIO = false;
 
     // contains all connected USB devices
     private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
@@ -57,6 +63,15 @@
     private ArrayList<UsbInterface> mNewInterfaces;
     private ArrayList<UsbEndpoint> mNewEndpoints;
 
+    // Attributes of any connected USB audio device.
+    //TODO(pmclean) When we extend to multiple, USB Audio devices, we will need to get
+    // more clever about this.
+    private int mConnectedUsbCard = -1;
+    private int mConnectedUsbDeviceNum = -1;
+    private boolean mConnectedHasPlayback = false;
+    private boolean mConnectedHasCapture = false;
+    private boolean mConnectedHasMIDI = false;
+
     @GuardedBy("mLock")
     private UsbSettingsManager mCurrentSettings;
 
@@ -102,6 +117,48 @@
         return false;
     }
 
+    // Broadcasts the arrival/departure of a USB audio interface
+    // card - the ALSA card number of the physical interface
+    // device - the ALSA device number of the physical interface
+    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
+    private void sendDeviceNotification(int card, int device, boolean enabled,
+            boolean hasPlayback, boolean hasCapture, boolean hasMIDI) {
+        // send a sticky broadcast containing current USB state
+        Intent intent = new Intent(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        intent.putExtra("state", enabled ? 1 : 0);
+        intent.putExtra("card", card);
+        intent.putExtra("device", device);
+        intent.putExtra("hasPlayback", hasPlayback);
+        intent.putExtra("hasCapture", hasCapture);
+        intent.putExtra("hasMIDI", hasMIDI);
+        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private boolean waitForAlsaFile(int card, int device, boolean capture) {
+        // These values were empirically determined.
+        final int kNumRetries = 5;
+        final int kSleepTime = 500; // ms
+        String alsaDevPath = "/dev/snd/pcmC" + card + "D" + device + (capture ? "c" : "p");
+        File alsaDevFile = new File(alsaDevPath);
+        boolean exists = false;
+        for (int retry = 0; !exists && retry < kNumRetries; retry++) {
+            exists = alsaDevFile.exists();
+            if (!exists) {
+                try {
+                    Thread.sleep(kSleepTime);
+                } catch (IllegalThreadStateException ex) {
+                    Slog.d(TAG, "usb: IllegalThreadStateException while waiting for ALSA file.");
+                } catch (java.lang.InterruptedException ex) {
+                    Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
+                }
+            }
+        }
+
+        return exists;
+    }
+
     /* Called from JNI in monitorUsbHostBus() to report new USB devices
        Returns true if successful, in which case the JNI code will continue adding configurations,
        interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
@@ -111,6 +168,25 @@
             int deviceClass, int deviceSubclass, int deviceProtocol,
             String manufacturerName, String productName, String serialNumber) {
 
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
+            // Audio Class Codes:
+            // Audio: 0x01
+            // Audio Subclass Codes:
+            // undefined: 0x00
+            // audio control: 0x01
+            // audio streaming: 0x02
+            // midi streaming: 0x03
+
+            // some useful debugging info
+            Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
+                    + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+        }
+
+        // OK this is non-obvious, but true. One can't tell if the device being attached is even
+        // potentially an audio device without parsing the interface descriptors, so punt on any
+        // such test until endUsbDeviceAdded() when we have that info.
+
         if (isBlackListed(deviceName) ||
                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
             return false;
@@ -135,6 +211,7 @@
             mNewInterfaces = new ArrayList<UsbInterface>();
             mNewEndpoints = new ArrayList<UsbEndpoint>();
         }
+
         return true;
     }
 
@@ -176,6 +253,9 @@
 
     /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
     private void endUsbDeviceAdded() {
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
+        }
         if (mNewInterface != null) {
             mNewInterface.setEndpoints(
                     mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
@@ -185,6 +265,17 @@
                     mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
         }
 
+        // Is there an audio interface in there?
+        final int kUsbClassId_Audio = 0x01;
+        boolean isAudioDevice = false;
+        for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < mNewInterfaces.size();
+                ntrfaceIndex++) {
+            UsbInterface ntrface = mNewInterfaces.get(ntrfaceIndex);
+            if (ntrface.getInterfaceClass() == kUsbClassId_Audio) {
+                isAudioDevice = true;
+            }
+        }
+
         synchronized (mLock) {
             if (mNewDevice != null) {
                 mNewDevice.setConfigurations(
@@ -200,10 +291,70 @@
             mNewInterfaces = null;
             mNewEndpoints = null;
         }
+
+        if (!isAudioDevice) {
+            return; // bail
+        }
+
+        //TODO(pmclean) The "Parser" objects inspect files in "/proc/asound" which we presume is
+        // present, unlike the waitForAlsaFile() which waits on a file in /dev/snd. It is not
+        // clear why this works, or that it can be relied on going forward.  Needs further
+        // research.
+        AlsaCardsParser cardsParser = new AlsaCardsParser();
+        cardsParser.scan();
+        // cardsParser.Log();
+
+        // But we need to parse the device to determine its capabilities.
+        AlsaDevicesParser devicesParser = new AlsaDevicesParser();
+        devicesParser.scan();
+        // devicesParser.Log();
+
+        // The protocol for now will be to select the last-connected (highest-numbered)
+        // Alsa Card.
+        mConnectedUsbCard = cardsParser.getNumCardRecords() - 1;
+        mConnectedUsbDeviceNum = 0;
+
+        if (!waitForAlsaFile(mConnectedUsbCard, mConnectedUsbDeviceNum, false)) {
+            return;
+        }
+
+        mConnectedHasPlayback = devicesParser.hasPlaybackDevices(mConnectedUsbCard);
+        mConnectedHasCapture = devicesParser.hasCaptureDevices(mConnectedUsbCard);
+        mConnectedHasMIDI = devicesParser.hasMIDIDevices(mConnectedUsbCard);
+
+        if (DEBUG_AUDIO) {
+            Slog.d(TAG,
+                    "usb: hasPlayback:" + mConnectedHasPlayback + " hasCapture:" + mConnectedHasCapture);
+        }
+
+        sendDeviceNotification(mConnectedUsbCard,
+                mConnectedUsbDeviceNum,
+                true,
+                mConnectedHasPlayback,
+                mConnectedHasCapture,
+                mConnectedHasMIDI);
     }
 
     /* Called from JNI in monitorUsbHostBus to report USB device removal */
     private void usbDeviceRemoved(String deviceName) {
+        if (DEBUG_AUDIO) {
+          Slog.d(TAG, "usb:UsbHostManager.usbDeviceRemoved() nm:" + deviceName);
+        }
+
+        if (mConnectedUsbCard != -1 && mConnectedUsbDeviceNum != -1) {
+            sendDeviceNotification(mConnectedUsbCard,
+                    mConnectedUsbDeviceNum,
+                    false,
+                    mConnectedHasPlayback,
+                    mConnectedHasCapture,
+                    mConnectedHasMIDI);
+            mConnectedUsbCard = -1;
+            mConnectedUsbDeviceNum = -1;
+            mConnectedHasPlayback = false;
+            mConnectedHasCapture = false;
+            mConnectedHasMIDI = false;
+        }
+
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 46d09f6..be13acc 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -137,7 +137,6 @@
 
     /**
      * Get the signal level as an asu value between 0..97, 99 is unknown
-     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      */
     @Override
     public int getAsuLevel() {
@@ -342,7 +341,7 @@
 
     /**
      * Construct a SignalStrength object from the given parcel
-     * where the TYPE_LTE token is already been processed.
+     * where the TYPE_CDMA token is already been processed.
      */
     private CellSignalStrengthCdma(Parcel in) {
         // CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio are written into
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index daef37a..992ef4b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -78,6 +78,12 @@
     }
 
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/CoreTests/android/core/NsdServiceInfoTest.java
new file mode 100644
index 0000000..5bf0167
--- /dev/null
+++ b/tests/CoreTests/android/core/NsdServiceInfoTest.java
@@ -0,0 +1,163 @@
+package android.core;
+
+import android.test.AndroidTestCase;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.StrictMode;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+public class NsdServiceInfoTest extends AndroidTestCase {
+
+    public final static InetAddress LOCALHOST;
+    static {
+        // Because test.
+        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
+        StrictMode.setThreadPolicy(policy);
+
+        InetAddress _host = null;
+        try {
+            _host = InetAddress.getLocalHost();
+        } catch (UnknownHostException e) { }
+        LOCALHOST = _host;
+    }
+
+    public void testLimits() throws Exception {
+        NsdServiceInfo info = new NsdServiceInfo();
+
+        // Non-ASCII keys.
+        boolean exceptionThrown = false;
+        try {
+            info.setAttribute("猫", "meow");
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // ASCII keys with '=' character.
+        exceptionThrown = false;
+        try {
+            info.setAttribute("kitten=", "meow");
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // Single key + value length too long.
+        exceptionThrown = false;
+        try {
+            String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "ooooooooooooooooooooooooooooong";  // 248 characters.
+            info.setAttribute("longcat", longValue);  // Key + value == 255 characters.
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // Total TXT record length too long.
+        exceptionThrown = false;
+        int recordsAdded = 0;
+        try {
+            for (int i = 100; i < 300; ++i) {
+                // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
+                String key = String.format("key%d", i);
+                info.setAttribute(key, "12345");
+                recordsAdded++;
+            }
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertTrue(100 == recordsAdded);
+        assertTrue(info.getTxtRecord().length == 1300);
+    }
+
+    public void testParcel() throws Exception {
+        NsdServiceInfo emptyInfo = new NsdServiceInfo();
+        checkParcelable(emptyInfo);
+
+        NsdServiceInfo fullInfo = new NsdServiceInfo();
+        fullInfo.setServiceName("kitten");
+        fullInfo.setServiceType("_kitten._tcp");
+        fullInfo.setPort(4242);
+        fullInfo.setHost(LOCALHOST);
+        checkParcelable(fullInfo);
+
+        NsdServiceInfo noHostInfo = new NsdServiceInfo();
+        noHostInfo.setServiceName("kitten");
+        noHostInfo.setServiceType("_kitten._tcp");
+        noHostInfo.setPort(4242);
+        checkParcelable(noHostInfo);
+
+        NsdServiceInfo attributedInfo = new NsdServiceInfo();
+        attributedInfo.setServiceName("kitten");
+        attributedInfo.setServiceType("_kitten._tcp");
+        attributedInfo.setPort(4242);
+        attributedInfo.setHost(LOCALHOST);
+        attributedInfo.setAttribute("color", "pink");
+        attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
+        attributedInfo.setAttribute("adorable", (String) null);
+        attributedInfo.setAttribute("sticky", "yes");
+        attributedInfo.setAttribute("siblings", new byte[] {});
+        attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
+        attributedInfo.removeAttribute("sticky");
+        checkParcelable(attributedInfo);
+
+        // Sanity check that we actually wrote attributes to attributedInfo.
+        assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
+        String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
+        assertTrue(sound.equals("にゃあ"));
+        byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
+        assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
+        assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
+    }
+
+    public void checkParcelable(NsdServiceInfo original) {
+        // Write to parcel.
+        Parcel p = Parcel.obtain();
+        Bundle writer = new Bundle();
+        writer.putParcelable("test_info", original);
+        writer.writeToParcel(p, 0);
+
+        // Extract from parcel.
+        p.setDataPosition(0);
+        Bundle reader = p.readBundle();
+        reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
+        NsdServiceInfo result = reader.getParcelable("test_info");
+
+        // Assert equality of base fields.
+        assertEquality(original.getServiceName(), result.getServiceName());
+        assertEquality(original.getServiceType(), result.getServiceType());
+        assertEquality(original.getHost(), result.getHost());
+        assertTrue(original.getPort() == result.getPort());
+
+        // Assert equality of attribute map.
+        Map<String, byte[]> originalMap = original.getAttributes();
+        Map<String, byte[]> resultMap = result.getAttributes();
+        assertEquality(originalMap.keySet(), resultMap.keySet());
+        for (String key : originalMap.keySet()) {
+            assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
+        }
+    }
+
+    public void assertEquality(Object expected, Object result) {
+        assertTrue(expected == result || expected.equals(result));
+    }
+
+    public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
+        assertTrue(null == shouldBeEmpty.getTxtRecord());
+    }
+}
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index bf35db4..a0b2d1a 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -97,6 +97,7 @@
         setLowProfile(true);
         setFullscreen(true);
         setContentView(R.layout.dream);
+        setScreenBright(false);
 
         mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c8eefe05c..0ad3456 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -867,14 +867,5 @@
             </intent-filter>
         </activity>
 
-        <activity
-                android:name="IsolationVolumeActivity"
-                android:label="Reordering/IsolationVolume">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="com.android.test.hwui.TEST" />
-            </intent-filter>
-        </activity>
-
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/res/layout/isolation.xml b/tests/HwAccelerationTest/res/layout/isolation.xml
deleted file mode 100644
index e66db19..0000000
--- a/tests/HwAccelerationTest/res/layout/isolation.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="#f55">
-    <!-- Left and right layouts are not isolated volumes, so the text views
-         will interleave since they share an isolated z volume-->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:orientation="vertical">
-            <TextView style="@style/TopLeftReorderTextView"/>
-            <TextView style="@style/BottomLeftReorderTextView"/>
-        </LinearLayout>
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:translationY="50dp"
-            android:orientation="vertical">
-            <TextView style="@style/TopRightReorderTextView"/>
-            <TextView style="@style/BottomRightReorderTextView"/>
-        </LinearLayout>
-    </LinearLayout>
-
-    <!-- Left and right volumes are isolated by default, so no interleaving will be seen. -->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:orientation="vertical">
-            <TextView style="@style/TopLeftReorderTextView"/>
-            <TextView style="@style/BottomLeftReorderTextView"/>
-        </LinearLayout>
-        <LinearLayout
-            android:layout_width="0dp"
-            android:layout_height="200dp"
-            android:layout_weight="1"
-            android:translationY="50dp"
-            android:orientation="vertical">
-            <TextView style="@style/TopRightReorderTextView"/>
-            <TextView style="@style/BottomRightReorderTextView"/>
-        </LinearLayout>
-    </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java
deleted file mode 100644
index d5c93f2..0000000
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/IsolationVolumeActivity.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.android.test.hwui;
-
-import android.os.Bundle;
-import android.app.Activity;
-
-public class IsolationVolumeActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.isolation);
-    }
-}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 6ca1aa7..bb2bebf 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -46,8 +46,8 @@
             android:rotation="46.757"
             android:pivotX="162"
             android:pivotY="173.5"
-            android:fill="?attr/android:colorControlNormal"
-            android:stroke="?attr/android:colorControlNormal"
+            android:fill="?android:attr/colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="3"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
@@ -56,7 +56,7 @@
         <path
             android:name="box3"
             android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z"
-            android:stroke="?attr/android:colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="10"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
@@ -65,7 +65,7 @@
         <path
             android:name="box4"
             android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z"
-            android:stroke="?attr/android:colorControlNormal"
+            android:stroke="?android:attr/colorControlNormal"
             android:strokeWidth="30"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 743a26c..757cdd2 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -23,22 +23,13 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IApplicationToken;
-import android.view.IInputFilter;
-import android.view.IOnKeyguardExitResult;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.IWindowSession;
 
-import java.util.List;
+import java.lang.Override;
 
 /**
  * Basic implementation of {@link IWindowManager} so that {@link Display} (and
@@ -462,4 +453,22 @@
         // TODO Auto-generated method stub
         return false;
     }
+
+    @Override
+    public void enableScreenIfNeeded() throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public boolean clearWindowContentFrameStats(IBinder token) throws RemoteException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public WindowContentFrameStats getWindowContentFrameStats(IBinder token)
+            throws RemoteException {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index b9f2ed9..4eb70aa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -28,7 +28,7 @@
 public class BridgePowerManager implements IPowerManager {
 
     @Override
-    public boolean isScreenOn() throws RemoteException {
+    public boolean isInteractive() throws RemoteException {
         return true;
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index df576d2..d32f6ee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -58,11 +58,6 @@
     }
 
     @Override
-    public void dispatchScreenState(boolean on) throws RemoteException {
-        // pass for now.
-    }
-
-    @Override
     public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
         // pass for now.
     }